【JAVA】SpringMVC(下)—— SSM整合&异常处理器

目录

【SpringMVC】

【REST风格】—— Representational State Transfer

【行为区分】

【使用】

【标准开发】

【SSM整合】

【整合流程】

【Spring整合MyBatis】

【Spring整合SpringMVC】

【表现层数据封装】

【异常处理器】

【使用】

【项目异常分类】

【项目异常处理方案】

【异常处理】

【拦截器】

【拦截器与过滤器的区别】

【使用】

【执行流程】

【拦截器参数】


【SpringMVC】

【REST风格】—— Representational State Transfer

【概述】

表现形式状态转换

【描述】

传统风格资源描述形式

  • http://localhost/user/getById?id=1
  • http://localhost/user/saveUser

REST风格描述形式

  • http://localhost/user/1
  • http://localhost/user

【优点】

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

【行为区分】

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

  • http://localhost/users  查询全部用户信息                GET(查询)
  • http://localhost/users/1  查询指定用户信息             GET(查询)
  • http://localhost/users  添加用户信息                        POST(新增/保存)
  • http://localhost/users  修改用户信息                        PUT(修改/更新)
  • http://localhost/users/1  删除用户信息                     DELETE(删除)

根据REST风格对资源进行访问称为RESTful

【注意】

  • 上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范
  • 描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts……

【使用】

1、设置http请求动作

@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody User user){
    System.out.println("user save..." + user);
    return "{'module':'user save'}";
}

@RequestMapping(value = "/users" ,method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
    System.out.println("user update..."+user);
    return "{'module':'user update'}";
}

2、设置请求参数(路径变量)

@RequestMapping(value = "/users/{id}" ,method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
    System.out.println("user delete..." + id);
    return "{'module':'user delete'}";
}

【@RequestMapping】

  • 名称:@RequestMapping
  • 类型:方法注解
  • 作用:设置当前控制器方法请求访问路径
  • 属性:
    • value(默认):请求访问路径
    • method:http请求动作,标准动作(GET/POST/PUT/DELETE)

例:

@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
public String save(@RequestBody User user){
    System.out.println("user save..." + user);
    return "{'module':'user save'}";
}

【@PathVariable】

  • 名称:@PathVariable
  • 类型:形参注解
  • 作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

例:

@RequestMapping(value = "/users/{id}" ,method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
    System.out.println("user delete..." + id);
    return "{'module':'user delete'}";
}

【注意】

@RequestBody、@RequestParam、@PathVariable的区别

  • @RequestParam用于接收url地址传参或表单传参
  • @RequestBody用于接收json数据
  • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数

应用

  • 开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
  • 如果发送非json格式数据,选用@RequestParam接收请求参数
  • 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值

【标准开发】

【@RestController】

  • 名称:@RestController
  • 类型:类注解
  • 作用:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能

例:

@RestController
public class BookController {
}

【@GetMapping、@PostMapping、@PutMapping、@DeleteMapping】

  • 名称:@GetMapping  @PostMapping  @PutMapping  @DeleteMapping
  • 类型:方法注解
  • 作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求
  • 属性:value(默认):请求访问路径
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
    System.out.println("book getById..."+id);
    return "{'module':'book getById'}";
}

【SSM整合】

【整合流程】

1.创建工程

2.SSM整合

  • Spring
    • SpringConfig
  • MyBatis
    • MybatisConfig
    • JdbcConfig
    • jdbc.properties
  • SpringMVC
    • ServletConfig
    • SpringMvcConfig

3.功能模块

  • 表与实体类
  • dao(接口+自动代理)
  • service(接口+实现类)
    • 业务层接口测试(整合JUnit)
  • controller
    • 表现层接口测试(PostMan)

【Spring整合MyBatis】

  • 配置
    • SpringConfig
    • JDBCConfig、jdbc.properties
    • MyBatisConfig
  • 模型
    • Book
  • 数据层标准开发
    • BookDao
  • 业务层标准开发
    • BookService
    • BookServiceImpl
  • 测试接口
    • BookServiceTest
  • 事务处理

【Spring整合SpringMVC】

  • SpringMVC配置类
  • 基于Restful的Controller开发

【表现层数据封装】

1、设置统一数据返回结果类

public class Result {
    private Object data;
    private Integer code;
    private String msg;
}

【注意】

  • Result类中的字段并不是固定的,可以根据需要自行增减
  • 提供若干个构造方法,方便操作

2、设置统一数据返回结果编码

public class Code {
    public static final Integer SAVE_OK = 20011;
    public static final Integer DELETE_OK = 20021;
    public static final Integer UPDATE_OK = 20031;
    public static final Integer GET_OK = 20041;

    public static final Integer SAVE_ERR = 20010;
    public static final Integer DELETE_ERR = 20020;
    public static final Integer UPDATE_ERR = 20030;
    public static final Integer GET_ERR = 20040;
}

【注意】 

Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK

3、根据情况设定合理的Result

@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        Book book = bookService.getById(id);
        Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
        String msg = book != null ? "" : "数据查询失败,请重试!";
        return new Result(code,book,msg);
    }
}

【异常处理器】

出现异常现象的常见位置与常见原因:

  • 框架内部抛出的异常:因使用不合规导致
  • 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
  • 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
  • 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
  • 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

【注意】

  1. 所有的异常均抛出到表现层进行处理
  2. 表现层处理异常,使用AOP思想

【使用】

集中的、统一的处理项目中出现的异常

@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        return new Result(666,null,"异常");
    }
}

【@RestControllerAdvice】

  • 名称:@RestControllerAdvice
  • 类型:类注解
  • 作用:为Rest风格开发的控制器类做增强

【注意】

此注解自带@ResponseBody注解与@Component注解,具备对应的功能

【@ExceptionHandler】

  • 名称:@ExceptionHandler
  • 类型:方法注解
  • 作用:设置指定异常的处理方案,功能等同于控制器方法,出现异常后终止原始控制器执行,并转入当前方法执行

【注意】

此类方法可以根据处理的异常不同,制作多个方法分别处理对应的异常

【项目异常分类】

  • 业务异常(BusinessException)
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常(SystemException)
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常(Exception)
    • 编程人员未预期到的异常

【项目异常处理方案】

业务异常(BusinessException)

  • 发送对应消息传递给用户,提醒规范操作

系统异常(SystemException)

  • 发送固定消息传递给用户,安抚用户
  • 发送特定消息给运维人员,提醒维护
  • 记录日志

其他异常(Exception)

  • 发送固定消息传递给用户,安抚用户
  • 发送特定消息给编程人员,提醒维护(纳入预期范围内)
  • 记录日志

【异常处理】

1、自定义项目系统级异常

public class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code,String message) {
        super(message);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    public SystemException(Integer code, Throwable cause) {
        super(cause);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }
}

2、自定义项目业务级异常

public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

    public BusinessException(Integer code, Throwable cause) {
        super(cause);
        this.code = code;
    }

    public BusinessException(Integer code, String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.code = code;
    }
}

3、自定义异常编码

public class Code {
    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer SYSTEM_TIMEOUT_ERR = 50001;
    public static final Integer SYSTEM_UNKNOW_ERR=59999;

    public static final Integer BUSINESS_ERR = 60002;
}

4、触发自定义异常

    public Book getById(Integer id) {
        if(id==1){
            throw new BusinessException(Code.BUSINESS_ERR,"请勿进行非法操作");
        }
        try {
            int i=1/0;
        }catch (Exception ex){
            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请稍后再试");
        }
        return bookDao.getById(id);
    }

5、拦截并处理异常

@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex) {
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex) {
        return new Result(ex.getCode(), null, ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex) {
        return new Result(Code.SYSTEM_UNKNOW_ERR, null, "系统异常,请稍后再试");
    }
}

【拦截器】

【概述】

是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

【作用】

  • 在指定的方法调用前后执行预先设定的代码
  • 阻止原始方法的执行

【拦截器与过滤器的区别】

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

【使用】

1、声明拦截器的bean,并实现HandlerInterceptor接口(注意:扫描加载bean)

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

2、定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置)

​@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
    }
}

​

3、添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

【可使用标准接口WebMvcConfigurer简化开发】(注意:侵入式较强)

@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer{
    @Autowired
    private ProjectInterceptor projectInterceptor;
   
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
    }
}

【执行流程】

【拦截器参数】

【前置处理】

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }

【参数】

  • request:请求对象
  • response:响应对象
  • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装

【返回值】

返回值为false,被拦截的处理器将不执行

【后置处理】

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

【参数】

modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

【完成后处理】

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }

【参数】

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

【多拦截器执行顺序】

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

【注意】

与过滤器链执行类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lx_Hy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值