参考资料
SpringMvc的工作流程
SpringMvc提供的请求转发和重定向
在SpringMVC中仍然可以使用传统方式实现转发和重定向
request.getRequestDispatcher("").forward(request, response);
response.sendRedirect("");
在SpringMVC中也提供了快捷方法实现转发和重定向
只要在返回视图时,使用如下方式指定即可:
redirect:/xxx.action
forward:/xxx.action
SpringMvc的注解
@RequestParam注解、@ResponseBody和@PathVariable
总结:
@ResponseBod支持请求体的Json格式
@PathVariable支持RestFull风格的url(请求行)
@@RequestParam注解支持url拼接的请求行,同时支持表单格式的请求体(Content-type为application/x-www-form-urlencoded(原生表单)或multipart/form-data(上传文件的表单))
@Resource和@Autowired
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
@Autowired:是按照类型注入
@Resourc:是按照类型和name属性进行匹配注入(默认按 byName自动注入,按其默认规则没有找到所需要注入的Bean时,则采用byType的方式寻找)。注解直接标注变量时省略name属性,则那么name值默认与所标注变量名相同。
@Repository、@Service、@Controller、@Component
持久层:@Repository(mabaitis中的@Mapper)
业务层:@Service
控制层:@Controller
中立类:@Component (对那些比较中立的类进行注释)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
注解中value属性对xml中Bean标签的id值。是Bean对象在Spring容器中的唯一标识。@Resource默认按照ByName查找就是这个value对应的值,这两个是相互匹配的。如果不设置注解的value属性,默认别名就是当前类名,但是首字母小写。
@ModelAttribute
详情参考:https://www.jianshu.com/p/0ec4e7afb7ed
在SpringMVC的Controller中使用@ModelAttribute时,其位置包括下面三种:
1.应用在方法上(被@ModelAttribute修饰的方法会在Controller中被@RequestMapping修饰的方法之前优先执行)
2.应用在方法的参数上(把参数封装到Model域中返回给页面,相当于request作用域)
3.应用在方法上,并且方法也使用了@RequestMapping(也是将数据封装到Model中返回给页面)
实际开发使用:根据1的特性,在BaseContrroller(Controller的基类)写一个被@ModelAttribute修饰的方法处理一些逻辑(例如:在这个方法里对Token令牌进行验证等。)
Springmvc跨域请求
@CrossOrigin注解支持跨域请求(用在Controller层)
SpringMvc的文件上传
使用transferTo()方法
@RequestMapping("/upload.do")
public void upload(@RequestParam("file") MultipartFile file, HttpServletResponse response){
//File newfile = new File("D:\\\\新桌面");
response.setContentType("text/html;charset=utf-8");
String path = "D:\\新桌面\\"+file.getOriginalFilename();
File newfile = new File(path);
System.out.println(file);
try {
file.transferTo(newfile);
response.getWriter().println("上传成功");
return;
} catch (Exception e) {
System.out.println("出现异常");
}
}
SpringMvc的异常处理
实际开发采取的方式:全局处理使用@controlleradvice 注解+@ExceptionHandler
CustomException(自定义异常实体类)
package com.example.demo.configurer.exception;
/**
* 自定义异常类
*/
public class CustomException extends RuntimeException {
//异常错误编码
private int code ;
//异常信息
private String message;
private CustomException(){}
public CustomException(CustomExceptionType exceptionTypeEnum, String message) {
this.code = exceptionTypeEnum.getCode();
this.message = message;
}
public int getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
CustomExceptionType(自定义异常枚举类)
package com.example.demo.configurer.exception;
/**
* 自定义异常枚举类
* @author czf
*/
public enum CustomExceptionType {
USER_INPUT_ERROR(400,"用户输入异常"),
SYSTEM_ERROR (500,"系统服务异常"),
USER_PERMISSION_ERROR(403,"用户没有权限"),
OTHER_ERROR(999,"其他未知异常"),
TOKEN_OUT(666,"token失效异常");
CustomExceptionType(int code, String typeDesc) {
this.code = code;
this.typeDesc = typeDesc;
}
private String typeDesc;//异常类型中文描述
private int code; //code
public String getTypeDesc() {
return typeDesc;
}
public int getCode() {
return code;
}
}
ModelViewException(将异常信息返回给视图层)
package com.example.demo.configurer.exception;
/**
* 视图异常类
*/
public class ModelViewException extends RuntimeException {
//异常错误编码
private int code ;
//异常信息
private String message;
public static ModelViewException transfer(CustomException e) {
return new ModelViewException(e.getCode(),e.getMessage());
}
private ModelViewException(int code, String message){
this.code = code;
this.message = message;
}
int getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
WebExceptionHandler(全局异常处理器:只要抛出异常都会经过处理器)
package com.example.demo.configurer.exception;
import com.example.demo.response.Result;
import com.example.demo.response.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 全局异常捕捉处理,异常处理器
* @author czf
*/
@Slf4j
//全局异常捕捉处理
@ControllerAdvice
public class WebExceptionHandler {
/**
* 异常信息封装给视图:处理ModelViewException类型的异常
* 如果不需要返回json数据,而要渲染某个页面模板返回给浏览器
* @param req
* @param e
* @return
*/
@ExceptionHandler(ModelViewException.class)
public ModelAndView viewExceptionHandler(HttpServletRequest req, ModelViewException e) {
ModelAndView modelAndView = new ModelAndView();
//将异常信息设置如modelAndView
modelAndView.addObject("exception", e);
modelAndView.addObject("url", req.getRequestURL());
modelAndView.setViewName("error");
//返回ModelAndView
return modelAndView;
}
/**
* 方法参数异常处理器:处理MethodArgumentNotValidException类型的异常
* @param ex
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Result handleBindException(MethodArgumentNotValidException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
log.error("MethodArgumentNotValidException错误信息:", ex);
return ResultGenerator.genErrorResult(new CustomException(CustomExceptionType.USER_INPUT_ERROR,fieldError.getDefaultMessage()));
}
/**
* 方法参数异常处理器:处理BindException类型的异常
* @param ex
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public Result handleBindException(BindException ex) {
FieldError fieldError = ex.getBindingResult().getFieldError();
log.error("BindException错误信息:", ex);
return ResultGenerator.genErrorResult(new CustomException(CustomExceptionType.USER_INPUT_ERROR,fieldError.getDefaultMessage()));
}
/**
* 自定义异常处理器:处理自定义类型的异常
* @param e
* @return
*/
@ExceptionHandler(CustomException.class)
@ResponseBody
public Result customerException(CustomException e) {
log.error("customerException错误信息:", e);
if(e.getCode() == CustomExceptionType.SYSTEM_ERROR.getCode()){
//400异常不需要持久化,将异常信息以友好的方式告知用户就可以
//TODO 将500异常信息持久化处理,方便运维人员处理
}
return ResultGenerator.genErrorResult(e);
}
/**
* 兜底的异常处理器
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Result exception(Exception e) {
log.error("Exception错误信息(未知):", e);
//TODO 将异常信息持久化处理,方便运维人员处理
//没有被程序员发现,并转换为CustomException的异常,都是其他异常或者未知异常.
return ResultGenerator.genErrorResult(new CustomException(CustomExceptionType.OTHER_ERROR,"未知异常"));
}
}
ResultGenerator(响应数据封装异常信息)
/**
* 封装异常信息数据
* 请求出现异常时的响应数据封装
* 失败状态码 500 同CustomExceptionType枚举类
* 失败信息 服务器报错
* 成功状数据 ""
*/
public static Result genErrorResult(CustomException e) {
Result resultException = new Result();
resultException.setCode(e.getCode());
if(e.getCode() == CustomExceptionType.USER_INPUT_ERROR.getCode()){
resultException.setMessage(e.getMessage());
}else if(e.getCode() == CustomExceptionType.SYSTEM_ERROR.getCode()){
resultException.setMessage(e.getMessage() + ",系统出现异常,请联系管理员!");
}else if (e.getCode()==CustomExceptionType.TOKEN_OUT.getCode()){
resultException.setMessage(e.getMessage());
}
else{
resultException.setMessage("系统出现未知异常,请联系管理员!");
}
return resultException;
}