参考资料

官方文档

SpringMvc的工作流程

SpringMvc知识点总结_spring
SpringMvc知识点总结_异常处理_02

SpringMvc提供的请求转发和重定向

在SpringMVC中仍然可以使用传统方式实现转发和重定向
request.getRequestDispatcher("").forward(request, response);
response.sendRedirect("");
在SpringMVC中也提供了快捷方法实现转发和重定向
只要在返回视图时,使用如下方式指定即可:
redirect:/xxx.action
forward:/xxx.action

SpringMvc的注解

@RequestParam注解、@ResponseBody和@PathVariable

SpringMvc知识点总结_异常信息_03
总结:
@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知识点总结_异常处理_04
SpringMvc知识点总结_mvc_05

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;
}