SpringMVC2

SpringMVC让你的C层更加高效

springMVC(下集)

  1. SpringMVC 的常用注解
  2. SpringMVC 静态资源的处理
  3. SpringMVC 的文件上传和下载
  4. SpringMVC 的统一异常处理
  5. SpringMVC 的拦截器
  6. SpringMVC 的自动校验

springmvc常用注解

使用cookie获取页面设置的cookie值,代码示例:

  1. 构建页面进行cookie的值的设置
1
2
3
4
5
6
7
8
9
10
<head>
<script type="text/javascript">
//(path)必须要填写,因为JS的默认路径是当前页,如果不填,此cookie只在当前页面生效!~
document.cookie="name=wwj;path=/"
document.cookie="age=32;path=/"
</script>
</head>
<body>
<a href="testCookie">查看Cookie</a>
</body>
  1. 后台业务代码
1
2
3
4
5
6
7
8
9
@Controller
public class CookieController {
@RequestMapping("/testCookie")
public String testCookie(@CookieValue(value = "name", required = false) String name,
@CookieValue(value = "age", required = false) Integer age) {
System.out.println(name + "," + age);
return "hello";
}
}
  1. 操作访问,先访问jsp页面进行cookie值的设置。在进行请求的访问

使用@SessionAttributes将数据放入session作用域中

需要注意的是@SessionAttributes只能用在类上

常用的设置@SessionAttributes(value={“user1”, “user2”}) 会将model中属性名为user1和user2的属性添加到会话中

1
2
3
4
5
6
7
8
9
10
@SessionAttributes(value={"user"})
@Controller
public class SessionController {

@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
model.addAttribute("user", "wwj");
return "success";
}
}

访问连接,分别在不用的页面进行取值

使用@ModelAttribute

  1. 注释在一个普通方法(初始化数据)
1
2
3
4
5
//构建一个模型
public class Girl {
private String name;
private int age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
public class ModelController {
@ModelAttribute("girl")
public Girl init(Model model){
Girl g = new Girl();
g.setAge(28);
g.setName("菲菲");
return g;
}
@RequestMapping("/m1")
public String m1(Model model) {
System.out.println(model.containsAttribute("girl"));
return "msg";
}
}
  1. 直接接收restful格式并进行封装
  • 路径请求 <a href="m2/wwj/32">restful操作</a>

  • 接收restful

1
2
3
4
5
@RequestMapping("/m2/{name}/{age}")
public String m1(@ModelAttribute Girl girl) {
System.out.println(girl.getName()+girl.getAge());
return "msg";
}

注意数据:数据被封装到modelattr中,同时也是在model中的

设置请求方式 (了解)

@RequestMapping(value=”m3”,method=RequestMethod.POST)

通过method来设置http的请求方式

总结:其实不在乎注解的与多少,毕竟是属于对servlet的包装,可以假定不管使用什么方式,接收到前台所传递的参数


springMVC对于静态资源的处理

  1. 使用 <mvc:resources> 掌握

http://localhost:8080/springmvc001/usrjs.jsp

IMAGE

静态资源在加载的时候,被拦截了。这个时候需要我们在springmvc中标注哪些为静态资源,不受springmvc进行拦截

<mvc:resources location="/js/" mapping="/js/**"/>

location代表着webcontext容器下路径。映射所有js下面的资源为静态资源

观察浏览器资源加载列表

  1. 使用<mvc:default-servlet-handler/>(掌握)

SpringMVC的文件上传和下载

文件上传

  1. 构建form表单 需要设置enctype(编码格式) 为 multipart/form-data 不仅包含文本数据,还包含文件数据
1
2
3
4
5
<!-- 多文件上传 -->
<form action="uploadUrl" method="post" enctype="multipart/form-data">
<input type="file" name="filename" /> <input type="file"
name="filename" /> <input type="submit" value="文件上传" />
</form>
  1. 引入对应的jar包

Commons-fileupload.jar和commons-io.jar 2个包属于依赖关系翻译过来就是通用的上传与通用的读写操作

  1. 设置对应的上传数据要求在springmvc.xml中
1
2
3
4
5
6
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置请求编码格式,必须与JSP中的pageEncoding属性一致 -->
<property name="defaultEncoding" value="UTF-8" />
<!-- 设置允许上传文件的最大值(2MB),单位为字节 -->
<property name="maxUploadSize" value="2097152" />
</bean>
  1. 处理对应上传的处理类

IMAGE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Controller
public class UploadController {

@RequestMapping("/uploadUrl")
public String handleFormUpload(@RequestParam("filename") MultipartFile[] files,HttpServletRequest req){
//判断文件是否存在
if(files.length>0){
for (MultipartFile multipartFile : files) {
//获取上传文件的原始名字
String originalFilename = multipartFile.getOriginalFilename();
//一般决定于项目设计的时候所规范的路径
String dirPath = req.getServletContext().getRealPath("/upload/");
File filePath = new File(dirPath);
//如果保存文件的地址不存在,就先创建目录
if(!filePath.exists()) {
filePath.mkdirs();
}
String newFilename = UUID.randomUUID()+"_"+originalFilename;
try {
multipartFile.transferTo(new File(dirPath + newFilename));
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

return null;
}
}

注意:UUID 是 通用唯一识别码(Universally Unique Identifier),是一种软件建构的标准

IMAGE

使用ajax进行文件的上传

注意事项:

  1. 需要使用到js中一个叫做formData对象
  2. 尽量使用goole或者火狐浏览器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function testup(){
var form = new FormData(document.getElementById("tf"));
$.ajax({
url:"uploadUrl1",
type:"post",
data:form,
processData:false,
contentType:false,
success:function(data){
console.log(data)
if(data=="ok"){
alert("上传成功")
}else {
alert("上传失败")
}
}
});
}

注意:contentType 和 processData 设置为false 使其能够正确的对formdata进行处理

文件的下载

  1. 构建请求
1
2
<a href="downloadone">下载单文件</a>
<a href="downloadmore">下载多文件</a>
  1. 构建处理类:
  • 单文件下载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller
public class DownloadController {

@RequestMapping("/downloadone")
public ResponseEntity<byte[]> download(HttpServletRequest req) throws IOException {
// 这个路径由数据库中取出
String resourceName = "计划.txt";
// 指定全路径位置
File file = new File(req.getServletContext().getRealPath("/upload/")+resourceName);
HttpHeaders headers = new HttpHeaders();
// 避免出现文件名乱码
String filename = new String(resourceName.getBytes("iso-8859-1"),"utf-8");
//设置响应的内容 attachment 附件
headers.setContentDispositionFormData("attachment", filename);
// 设置响应的内容为流的方式
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);
}
  • 多文件需要考虑进行打包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@RequestMapping("/downloadmore")
public ResponseEntity<byte[]> download1s(HttpServletRequest req) throws IOException {

//数据库中提取
List<String> list = new ArrayList<String>();
list.add("计划.txt");
list.add("进度.txt");

//压缩后的文件名
String resourcesName = "test.zip";
//压缩后的全路径
String pathName = req.getServletContext().getRealPath("/upload/");
File zipFile = new File(pathName+resourcesName);
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));
//读取并写入到压缩包里面
InputStream input = null;
for (String str : list) {
String name = pathName+str;
input = new FileInputStream(new File(name));
zipOut.putNextEntry(new ZipEntry(str));
int temp = 0;
while((temp = input.read()) != -1){
zipOut.write(temp);
}
input.close();
}
zipOut.close();
File file = new File(pathName+resourcesName);
HttpHeaders headers = new HttpHeaders();
String filename = new String(resourcesName.getBytes("iso-8859-1"),"utf-8");
headers.setContentDispositionFormData("attachment", filename);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);

}

SpringMVC 的统一异常处理(掌握) (避免在controller中进行冗余的try catch操作)

  • 先自定义异常
1
2
3
4
5
6
7
8
9
10
11
12
/**
* 自定义异常
* @author Yun
*
*/
public class ServiceException extends RuntimeException {

public ServiceException(String msg){
super(msg);
}

}
  • 定义全局异常处理类 (需要用到@ControllerAdvice以及@ExceptionHandler(ServiceException.class))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@ControllerAdvice
public class GlobalExceptionResolver {
/**
* 处理所有业务异常
*
* @param e 业务异常
* @return json结果
*/
@ExceptionHandler(ServiceException.class)
@ResponseBody
public Girl handleOpdRuntimeException(ServiceException e) {
Girl g = new Girl();
g.setAge(18);
g.setName("wwj");
return g;
}

}
  • controller业务处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
public class Econtroller {

/**
* 测试返回异常信息
* @return
*/
@RequestMapping("/exception")
public void returnExceptionInfo() {
if (1 != 2) {
// 用户民错误或不存在异常
throw new ServiceException("错误");
}
}
}

注意:开发中,我们在设计业务功能模块,都需要配置对应的exception处理

SpringMVC 拦截器 (掌握) 拦截 Interceptor

拦截器是对过滤器操作的一种升华。拦截器本身的机制也是aop进行实现

  1. 操作方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MyInterceptor implements HandlerInterceptor{

@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("afterCompletion");
}

@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
// TODO Auto-generated method stub
System.out.println("postHandle");
}

@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
// TODO Auto-generated method stub
System.out.println("preHandle");
return true;
}

}
  1. 配置文件
1
2
3
4
5
6
7
8
9
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截所有的请求,这个必须写在前面,也就是写在【不拦截】的上面 -->
<mvc:mapping path="/**" />
<!-- 但是排除下面这些,也就是不拦截请求 -->
<mvc:exclude-mapping path="/login.html" />
<bean class="com.wwj.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
  1. 执行的顺序为

  2. preHandle 在业务处理器处理请求之前被调用(如果preHandle返回false)

  3. postHandle 在业务处理器处理请求执行完成后,生成视图之前执行

  4. afterCompletion 完全处理完请求后被调用,可用于清理资源等


SpringMVC 的自动校验(了解)

  1. 引入相关的jar包

IMAGE

  1. 构建实体类 (有一些注解可以对对象的某个字段进行检验)
1
2
3
4
5
6
7
8
9
10
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class User {

@NotNull(message="id不能为空!")
private int uid;
@NotBlank(message="用户名不能为空!")
private String uname;
}
  1. (将配置文件中拦截器代码剔除)
1
2
3
4
5
<form action="user1" method="post">
<input type="text" name="uid"/>
<input type="text" name="uname"/>
<button>提交</button>
</form>
  1. 控制代码中通过提供的errorObj来获取验证的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class Vcontroller {
@RequestMapping("/user1")
@ResponseBody
public User test(@Validated User user, BindingResult result) {
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
for (ObjectError error : errors) {
System.out.println(error.getDefaultMessage());
}
}
return user;
}
}