先回顾一下Spring实战——构建Spring Web应用程序中使用java配置构建的SpringMVC框架。以下会提供SpringMVC配置的替代方案。
注意:在Spring实战——构建Spring Web应用程序一文中说过:使用java配置SpringMVC时只支持Servlet3.0的容器,据我所知,目前在企业里大部分还是使用的xml进行配置。
1、使用纯xml配置SpringMVC
web.xml配置内容:
Archetype Created Web Application
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
springDispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc.xml
1
springDispatcherServlet
/
applicationContext.xml
spring-mvc.xml
完成以上配置即可实现SpringMVC的测试了。
参考以前的博客:springMVC上传图片
1、Spring提供了多种方式将异常转换为响应
①特定的Spring异常将会自动映射为指定的HTTP状态码
②异常上可以添加@responseStatus注解,从而将其映射为某一个指定的HTTP状态码
③在方法上面添加@ExceptionHandler注解,使其处理异常
2、Spring的一些异常会默认映射为HTTP状态码
Spring异常 | HTTP状态码 |
BindException | 400 - Bad Request |
ConversionNotSupportedException | 500 - Internal Server Error |
HttpMediaTypeNotAcceptableException | 406 - Not Acceptable |
HttpMediaTypeNotSupportedException | 415 - Unsupported Media Type |
HttpMessageNotReadableException | 400 - Bad Request |
HttpMessageNotWritableException | 500 - Internal Server Error |
HttpRequestMethodNotSupportedException | 405 - Method Not Allowed |
MethodArgumentNotValidException | 400 - Bad Request |
MissingServletRequestParameterException | 400 - Bad Request |
MissingServletRequestPartException | 400 - Bad Request |
NoSuchRequestHandlingMethodException | 404 - Not Found |
TypeMismatchException | 400 - Bad Request |
3、处理异常的方式:
①可以在Controller的业务方法中处理,再Catch代码块中返回到指定的错误页面,如下:
@RequestMapping("/testPage")
public String testPage(@Valid TUser tUser,
@RequestParam("file")MultipartFile file,
HttpServletRequest request,
Model model){
String path = request.getSession().getServletContext().getRealPath("upload");
String name = file.getOriginalFilename();
File targetFile = new File(path, name);
try {
file.transferTo(targetFile);
System.out.println("upload/"+name);
} catch (IllegalStateException e) {
e.printStackTrace();
return "errorPage";
} catch (IOException e) {
e.printStackTrace();
return "errorPage";
}
model.addAttribute("path", "/upload/"+name);
return "testPage";
}
②以上方法每个Controller中捕获异常都需要return一次错误页面,会比较麻烦,可以使用@ExceptionHandler注解,在Controller中写一个专门处理处理异常的方法,这样一来这个处理异常的方法就可以处理同一个控制器中所有处理器方法抛出的异常,如下(下面这段代码可以加在每一个Controller的方法中):
/**
* 本方法可以处理本控制器中所有的异常
* @return
*/
@ExceptionHandler(Exception.class)
public String errorPage(){
return "errorPage";
}
③在②中的方法虽然统一处理了当前Controller中的所有异常,但是如果在每一个Controller类中都添加一个处理异常的方法难免比较麻烦,这时我们可以将这个处理异常的方法写在所有Controller都要继承的父类里面,此时这一个方法就可以处理所有Controller的异常了。还有一个更简单的方法就是为控制器添加通知,使用@ControllerAdvice注解,如下(下面这个类可以处理所有Controller中的异常了):
/**
* @author 74790
* 异常通知控制器
*/
@ControllerAdvice
public class ExceptionCtrl {
@ExceptionHandler(Exception.class)
public String errorPage(){
return "errorPage";
}
}
1、当一个请求在Controller的方法内走完逻辑程序时,需要重定向到另一个Controller的方法,此时就需要用到重定向了,也就是redirect。问题来了,当前一个Controller重定向时,原始的请求就结束了,就会发起一个新的GET请求,此时在发起重定向的方法怎么发送数据给重定向的目标方法呢?两种方法:
①使用URL模板以路径变量和 / 或查询参数的形式传递数据
②通过flash属性发送数据
2、通过URL传递数据:
下面两个方法中,testPage会向testRedirect重定向,并会带着参数name和path传过去。
@RequestMapping("/testPage")
public String testPage(@Valid TUser tUser,
@RequestParam("file")MultipartFile file,
HttpServletRequest request,
Model model){
String path = request.getSession().getServletContext().getRealPath("upload");
String name = file.getOriginalFilename();
File targetFile = new File(path, name);
try {
file.transferTo(targetFile);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
model.addAttribute("path", "/upload/"+name);
model.addAttribute("name", name);
return "redirect:../testCtrl/testRedirect/{name}";
}
@RequestMapping("testRedirect/{name}")
public String testRedirect(Model model,@PathVariable("name")String name,
@RequestParam("path")String path){
System.out.println(name);
System.out.println(path);
model.addAttribute("path", path);
return "testPage";
}
3、在2中的方法重定向时通过URL带过去了两个参数name和path,但是这种方法始终只能传递一些简答的数据。如果在testPage查出了一个对象,而在testRedirect中需要使用这个对象,这时就需要把整个对象传递过去(当然,你也可以传递查询到这个对象的条件,然后再testRedirect中再查询一遍,但是这样似乎不太好),此时需要用flash,但是这里注意,在需要重定向的方法中已经不是使用的Model了,而是使用的RedirectAttributes,RedirectAttributes提供了Model的所有功能。代码如下:
@RequestMapping("/testPage")
public String testPage(@Valid TUser tUser,
@RequestParam("file")MultipartFile file,
HttpServletRequest request,
RedirectAttributes model){
String path = request.getSession().getServletContext().getRealPath("upload");
String name = file.getOriginalFilename();
File targetFile = new File(path, name);
try {
file.transferTo(targetFile);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
model.addAttribute("path", "/upload/"+name);
model.addAttribute("name", name);
model.addFlashAttribute("tUser", tUser);
return "redirect:../testCtrl/testRedirect/{name}";
}
@RequestMapping("testRedirect/{name}")
public String testRedirect(Model model,@PathVariable("name")String name,
@RequestParam("path")String path){
//本方法中TUser对象已经直接存在了flash中,在testPage对应的页面上使用EL表达式 ${tUser.userName} 就可以获取到userName
System.out.println(name);
System.out.println(path);
//判断flash中是否有tUser这个对象
boolean flag = model.containsAttribute("tUser");
System.out.println(flag);
model.addAttribute("path", path);
return "testPage";
}