SSM

SSM流程图

image.png
image.png

SSM流程解释

  • 客户端发送请求,传过来url和参数
  • 首先会到拦截器filter,拦截器拦截不安全连接
  • 经过拦截器以后来到核心控制器DispatcherServlet(框架提供),就是处理分发请求的控制器,也是MVC中的C,根据url映射找到对应的处理器(handler,是controller包下的类)来处理请求
  • 控制层的处理器hander找它里面的业务逻辑层的代码来完成具体业务
  • 业务逻辑层找持久层的代码来实现对数据库的操作
  • 持久层对数据库里数据操控并返回结果集合
  • 集合从持久层->业务逻辑层处理->控制层里的处理器handle->传到核心处理器DispatcherServlet使用jackson 的API(springboot封装的)讲数据处理成json字符串返回给用户端

MVC

image.png

概要设计

  • 需求
    • 为行政人员发布公告,通知提供遍历
  • 原型设计
    • 系统做完以后是什么样子的,先做一个设计稿

image.png

  • 表的设计
    • 公告内容中包含哪些字段 ```sql drop database if exists db_notice; create database if not exists db_notice default character set utf8; use db_notice; drop table if exists sys_notice; create table sys_notice ( id int(4) auto_increment comment ‘ID’, title varchar(50) not null comment ‘标题’, type char(1) not null comment ‘类型(1 通知 2 公告)’, content varchar(500) default null comment ‘公告内容’, status char(1) default ‘0’ comment ‘状态(0 正常 1 关闭)’, createdUser varchar(64) default ‘’ comment ‘创建者’, createTime datetime comment ‘创建时间’, modifiedUser varchar(64) default ‘’ comment ‘更新者’, modifiedTime datetime comment ‘更新时间’, remark varchar(255) comment ‘备注’, primary key (id)

)engine=innodb auto_increment=1 comment = ‘通知公告表’;

  1. - 技术分层架构
  2. - 分而治之-将复杂问题简单化
  3. - 技术栈的设计
  4. - 数据库端技术,服务端技术,客户端技术
  5. <a name="vQz4p"></a>
  6. ### 项目的步骤描述
  7. - SpringBoot初始化
  8. 1. 定义POJO对象SysNotice(用于在内存中封装通知信息)
  9. 1. 添加依赖
  10. 1. 添加配置文件
  11. 1. 创建Dao接口SysNoticeDao并使用@Mapper进行描述
  12. - @Mapper将对象的管理交给springIOC容器
  13. - Dao接口中添加增删改查等业务相关方法
  14. 5. 定义Dao接口对应的映射文件,并添加增删改查等相关方法对应的SQL映射
  15. 5. 定义单元测试类SysNoticeTests,并对Dao层增删改查等相关方法进行单元测试分析
  16. 5. 业务逻辑层接口
  17. 5. 业务逻辑层实现类
  18. - 这里最好也是测试一下service层的增删改查等业务相关方法
  19. 9. web
  20. - 返回数据规范
  21. - 控制层
  22. - 全局异常处理
  23. - 拦截器配置
  24. - 声明拦截器内容
  25. 10. postman发送post请求测试
  26. 10. 日志
  27. <a name="COvcZ"></a>
  28. ## 项目实现流程
  29. <a name="NhndC"></a>
  30. ### 目录结构
  31. - src
  32. - main
  33. - java
  34. - 主程序所在包下建包pojo,dao,service,web
  35. - pojo下是与数据库表对应的实体类
  36. - dao下的接口有数据库的增删改查方法
  37. - service下的接口是业务方法描述
  38. - servic.impl包下是接口的具体实现
  39. - web
  40. - web.pojo包下的实体类是返回数据的规范
  41. - web.exception包下是全局异常处理
  42. - web.controller包下的类是handler,处理器
  43. - web.config包下的类是拦截器配置
  44. - web.interceptor包下的类是拦截器的内容
  45. - resource
  46. - 建立包mapper.***
  47. - xml文件是dao下接口方法对数据库操作的具体实现
  48. - test
  49. - 主程序所在包下建包dao,service
  50. - dao包下的类测试dao层的方法
  51. - service包下的类测试service层的方法
  52. - pom.xml
  53. <a name="0qcn8"></a>
  54. ## 具体步骤
  55. <a name="ydvka"></a>
  56. #### 1.POJO下 实体类
  57. - IDEA装插件Lombok
  58. - 添加Lombok依赖
  59. ```xml
  60. <dependency>
  61. <groupId>org.projectlombok</groupId>
  62. <artifactId>lombok</artifactId>
  63. <optional>true</optional>
  64. </dependency>
  • 这个插件提供了注解让类不用再写set、get、toString、hashCode、equals等方法
    • @Data //添加此注解后,类中会自动添加setter,getter,toString,hashCode,equals等方法
    • @NoArgsConstructor //为类添加无参构造函数
    • @AllArgsConstructor //为类添加全参构造函数 ```java package com.cy.pj.sys.pojo; import java.util.Date; / @Setter,@Getter,@ToString,hashCode,equals = @Data /

@Data //添加此注解后,类中会自动添加setter,getter,toString,hashCode,equals等方法 @NoArgsConstructor //为类添加无参构造函数 @AllArgsConstructor //为类添加全参构造函数 public class SysNotice { / 公告 ID */ private Long id; / 公告标题 / private String title; /** 公告类型(1 通知 2 公告) / private String type; / 公告内容 */ private String content; / 公告状态(0 正常 1 关闭) / private String status; /** 创建时间 / /当使用DateTimeFormat注解描述此属性时,表示客户端需要按此格式为日期属性传入值 系统默认格式@DateTimeFormat(pattern = “yyyy/MM/dd HH:mm:ss”) DateTimeFormat与JsonFormat写的话全部写上 */ @DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) /@JsonFormat注解描述的属性,表示服务器端日期传给前端的格式, timezone表示时区,老外写的,日期不和我们的日期相对应,timezone让显示的日期和我们具体的时间相同/ @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”) private Date createTime; /** 修改时间/ @DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) @JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”) private Date modifiedTime; / 创建用户 */ private String createdUser; / 修改用户/ private String modifiedUser; /**备注/ private String remark;

/**get与set
@Override
public String toString() {
    return "SysNotice{" +
            "id=" + id +
            ", title='" + title + '\'' +
            ", type='" + type + '\'' +
            ", content='" + content + '\'' +
            ", status='" + status + '\'' +
            ", createTime=" + createTime +
            ", modifiedTime=" + modifiedTime +
            ", createdUser='" + createdUser + '\'' +
            ", modifiedUser='" + modifiedUser + '\'' +
            '}';
}
*/

}

<a name="2tpxH"></a>
#### 2.添加依赖
```xml
<!--jdbc依赖-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>
<!--mybatis依赖-->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.1.3</version>
</dependency>
<!--添加Spring web依赖(融入了mvc设计思想,并会关联一个tomcat服务)-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3.mybatis配置文件

#spring datasource
spring.datasource.url=jdbc:mysql:///db_notice?serverTimezone=GMT%2B8&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=tarena

#spring mybatis
#配置sql超时
mybatis.configuration.default-statement-timeout=30
#驼峰命名规则
mybatis.configuration.map-underscore-to-camel-case=true
#映射文件路径
mybatis.mapper-locations=classpath:/mapper/*/*.xml

#日志的等级与操作日志的输出位置
logging.level.com.cy=debug
logging.file.path=E:/TCGBIll/log/

4.数据持久层Dao

package com.cy.pj.sys.dao;

/**
 * @Mapper由mybatis框架定义,用于描述数据持久层
 */
@Mapper
public interface SysNoticeDao {
    /**将内存中的SysNotice对象,持久化到数据库*/
    int insertSysNotice(SysNotice sysNotice);

    /**
     * 删除
     * 基于条件查询通告信息
     * @param:notice
     * @return:返回查询到的通告信息
     */
    int deleteSysNotice(Long... ids);

    /**修改:将内存中的notice对象,更新到数据库*/
    int updateSysNotice(SysNotice sysNotice);

    /**
     * 基于id查询SysNotice信息
     * @param id 查询条件
     * @return 查询到的notice对象(存储表中的一行记录)
     * 说明:简单的sql映射可以直接将sql语句写到方法上面,以注解进行声明
     */
    @Select("select * from sys_notice where id=#{id}")
    SysNotice selectById(Long id);

    /**
     * 混合查询
     * 基于条件查询通告信息
     * @param:SysNotice
     * @return:返回查询到的通告信息
     */
    List<SysNotice> selectSysNotices(SysNotice sysNotice);
}

5.映射XML

  • XML中resultType(resultMap)的值与接口里对应方法的返回值类型相同
  • XML中parameterType(parameterMap)的值与接口里对应方法的参数类型相同

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.cy.pj.sys.dao.SysNoticeDao">
    <!--mybatis框架中在系统启动时,会对映射文件中的内容进行解析,每个元素(每个增、删、改、查操作为一个元素)
    会封装为一个MappedStatement对象,多个这样的对象会存储到map集合,Key为
    空间namespace+方法id,值为MappedStatement对象 Map<String,MappedStatement>-->
    <insert id="insertSysNotice" parameterType="com.cy.pj.sys.pojo.SysNotice">
       INSERT INTO db_notice.sys_notice
       (title, TYPE, content, STATUS, createdUser, createTime, modifiedUser, modifiedTime, remark)
       VALUES
       (
       #{title},#{type},#{content},#{status},#{createdUser},now(),#{modifiedUser},now(),#{remark}
       );
    </insert>
    
    <delete id="deleteSysNotice">
       <!--foreach 用于迭代一个数组或集合
       要判断传过来的可变参数不指向空,并且长度大于0,否则数组没元素也是白搭(语法报错)-->
       delete from sys_notice
       <where>
           <if test="ids!=null and ids.length>0 ">
               id in
               <foreach collection="ids" item="id" open="(" separator="," close=")">
                   #{id}
               </foreach>
           </if>
           or 1=2
       </where>
       <!--or 1=2表示前面if判断不成立,这个1=2判断不成功,不执行任何操作,不加1=2就要删除整个表了
       where标签对于直接相接的and 和 or ,标签会删除它们,也就是 where 1=2-->
    </delete>
    
    <update id="updateSysNotice" parameterType="com.cy.pj.sys.pojo.SysNotice">
       <!--对数据判断,当没更新某些数据时,不会使这些数据为null-->
       UPDATE db_notice.sys_notice
       <set>
           <if test="title!=null and title!=''">
               title = #{title} 
           </if>
           <if test="type!=null and type!=''">
               ,type = #{type} 
           </if>
           <if test="content!=null and content!=''">
               ,content = #{content} 
           </if>
           <if test="status!=null and status!=''">
               ,status = #{status} 
           </if>
           <if test="modifiedUser!=null and modifiedUser!=''">
               ,modifiedUser = #{modifiedUser} 
           </if>
               ,modifiedTime = now() 
           <if test="remark!=null and remark!=''">
               ,remark = #{remark}
           </if>
       </set>
       <where>
           id = #{id}
       </where>
       </update>
    
    <select id="selectSysNotices" resultType="com.cy.pj.sys.pojo.SysNotice">
       <!--对数据判断,当没插入数据时,不会更新原有的数据,当传入的是空字符串"",也不出现sql语法错误
       对于type,值只有1和2,可以放在开头提高sql语句效率-->
       select id, title, type, content, status, createdUser, createTime, modifiedUser, modifiedTime, remark
       FROM
       db_notice.sys_notice
       <where>
           <if test="type!=null and type!=''">
               type=#{type}
           </if>
           <if test="title!=null and title!=''">
               and title like concat("%",#{title},"%")
           </if>
           <if test="modifiedUser!=null and modifiedUser!=''">
               and modifiedUser like concat("%",#{modifiedUser},"%")
           </if>
       </where>
    </select>
    </mapper>
    

    6.测试dao层

    ```java package com.cy.pj.sys.dao;

import com.cy.pj.sys.pojo.SysNotice; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;

import java.util.Date; import java.util.List;

@SpringBootTest public class SysNoticeDaoTests {

@Autowired
private SysNoticeDao sysNoticeDao;//属性的对象由spring进行依赖注入

@Test
public void testInsertSysNotice(){
    SysNotice sysNotice = new SysNotice();
    sysNotice.setTitle("放假");
    sysNotice.setType("1");
    sysNotice.setContent("放假100天");
    sysNotice.setStatus("0");
    sysNotice.setCreatedUser("hu");
    sysNotice.setCreatedTime(new Date(System.currentTimeMillis()));
    sysNotice.setModifiedUser("iu");
    sysNotice.setModifiedTime(new Date(System.currentTimeMillis()));
    sysNotice.setRemark("无");
    int count = sysNoticeDao.insertSysNotice(sysNotice);
    System.out.println(count);
}

@Test
public void testDeleteSysNotice(){
    int count = sysNoticeDao.deleteSysNotice(1l,3l);
    System.out.println(count);
}

@Test
public void testUpdateSysNotice(){
    SysNotice sysNotice = new SysNotice();
    sysNotice.setId(7l);
    sysNotice.setTitle("国庆放假");
    sysNotice.setType("1");
    sysNotice.setContent("放假7天");
    int count = sysNoticeDao.updateSysNotice(sysNotice);
    System.out.println(count);
}

@Test
public void testSelectById(){
    SysNotice sysNotice = sysNoticeDao.selectById(7l);
    System.out.println(sysNotice);
}

@Test
public void testSelectSysNotices(){
    SysNotice sysNotice = new SysNotice();
    sysNotice.setTitle("国");
    sysNotice.setType("");
    sysNotice.setCreatedUser("iu");
    List<SysNotice> lists = sysNoticeDao.selectSysNotices(sysNotice);
    for (SysNotice list : lists) {
        System.out.println(list);
    }
}

}

<a name="tpeiz"></a>
#### 7.业务逻辑层接口
```java
package com.cy.pj.sys.service;

/**
 * 此对象为通告业务逻辑对象负责对通告业务做具体落地实现
 * 1)调用数据逻辑对象执行数据操作
 * 2)日志记录
 * 3)事务处理
 * 4)缓存
 * 5)权限
 * 6).............
 * */
public interface SysNoticeService {
    /**
     * 添加通告
     * @param sysNotice
     * @return
     */
    int insertSysNotice(SysNotice sysNotice);

    /**
     * 删除多条通告
     * @param ids
     * @return
     */
    int deleteSysNotice(Long[] ids);

    /**
     * 更新通告
     * @param sysNotice
     * @return
     */
    int updateSysNotice(SysNotice sysNotice);

    /**
     * 根据id查询通告
     * @param id
     * @return
     */
    SysNotice selectBySysNoticeId(Long id);

    /**
     * 根据条件查询通告
     * @param sysNotice
     * @return
     */
    List<SysNotice> selectBySysNotice(SysNotice sysNotice);

}

8.业务逻辑层实现类

  • 业务逻辑复杂,不能由Spring来管理对象,当然这里的业务逻辑还很简单,仅仅只是个中间站 ```java package com.cy.pj.sys.service.impl;

import com.cy.pj.sys.dao.SysNoticeDao; import com.cy.pj.sys.pojo.SysNotice; import com.cy.pj.sys.service.SysNoticeService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;

import java.util.List;

/**

  • @Service注解由spring提供,一般用于描述分层架构中的业务逻辑对象,这样的类会交给spring管理 / @Service public class SysNoticeServiceImpl implements SysNoticeService { /**创建日志门面API对象/ private static final Logger log=

         //通过工厂创建日志对象,控制台的信息到达一定容量就会被清除,打印到日志文件报错起来
         LoggerFactory.getLogger(SysNoticeServiceImpl.class);
    

    @Autowired SysNoticeDao sysNoticeDao;

    @Override public int insertSysNotice(SysNotice sysNotice) {

     int count = sysNoticeDao.insertSysNotice(sysNotice);
     return count;
    

    }

    @Override public int deleteSysNotice(Long[] ids) {

     int count = sysNoticeDao.deleteSysNotice(ids);
     return count;
    

    }

    @Override public int updateSysNotice(SysNotice sysNotice) {

     int count = sysNoticeDao.updateSysNotice(sysNotice);
     return count;
    

    }

    @Override public SysNotice selectBySysNoticeId(Long id) {

     SysNotice sysNotice = sysNoticeDao.selectById(id);
     return sysNotice;
    

    }

    @Override public List selectBySysNotice(SysNotice sysNotice) {

     //这里的{}表示占位符
     log.debug("start:{}",System.currentTimeMillis());
     List<SysNotice> lists = sysNoticeDao.selectSysNotices(sysNotice);
     log.debug("end:{}",System.currentTimeMillis());
     return lists;
    

    } } ```

    9.web的数据封装JsonResult

  • 通过此对象封装服务端响应到客户端的数据,让数据以一种规范化的格式呈现给客户端 ```java package com.cy.pj.sys.web.pojo;

public class JsonResult { /状态码*/ private Integer state = 1; //1表示OK,0表示Error /状态码对应的信息/ private String message=”ok”; /**封装正确的查询结果/ private Object data;

public JsonResult(){}
public JsonResult(String message){
    this.message = message;
}
public JsonResult(Integer state,String message){
    this(message);
    this.state = state;
}
public JsonResult(Object data){ //new JsonResult(list)
    this.data = data;
}
//当出现异常时,可以通过此构造方法对异常信息进行封装
public JsonResult(Throwable exception){ //new JsonResult(exception)
    this(0,exception.getMessage());
}
//get与set省略...

}

<a name="DmWhU"></a>
#### 10.web控制层controller

- 一个controller注解修饰的controller类是一个hander
- 请求 url 设计
- 普通方式
   - http://ip:port/方法路径/参数名1=参数值1&参数名2=参数值2......
- @PathVariable
   - rest风格传入参数  http://ip:port/方法路径/参数值
   - 不能处理pojo对象参数
- 请求方式设计
   - @RequestMapping (通用,适配所有请求方式) 
   - @GetMapping(处理 Get 请求,主要应用于查询) 
   - @PostMapping(处理 post 请求,主要应用于新增操作) 
   - @PutMapping(处理 put 请求,主要应用于更新操作) 
   - @DeleteMapping(处理 delete 请求,主要应用于删除操作)
- 请求方法参数类型设计
   - 直接量(8 中基本数据类型+String+Date+数组) 
   - Pojo 对象(必须提供 set 方法) 
   - Map 对象(必须使用@RequestParam 或@RequestBody 注解描述)
- 请求方法参数描述设计
   - @RequestParam(对传统风格 url 参数,请求方法中的 map 参数进行描述) 
      - 更改参数名
   - @PathVariable (从 rest 风格 url 中取{}变量的值注入给参数) 
      - rest风格
   - @DateTimeFormat (假如是 pojo 参数,可以直接描述 pojo 日期属性)
      - 规范客户端传入的日期格式
   - @RequestBody (将客户端 post 请求的 json 属性赋值给 pojo 或 map 参数) 
      - 客户端传json
      - 一个方法中多个参数只能有一个参数被requestbody修饰
- 响应结果封装及转换
   - @JsonFormat(描述 pojo 属性或 get 方法,转 json 时按指定格式转换)
   - @ResponseBody(尽量将响应结果转换为 json 格式) 
      - 服务器返回json数据

```java
package com.cy.pj.sys.web.controller;

/**
 * 这个类我们称之为控制层对象的处理器(Handler),
 * 通过此对象处理DispatcherServlet(核心控制器-Controller)分发的请求,具体的处理包括:
 * 1)定义请求url映射
 * 2)通过参数对象封装请求参数数据
 * 3)调用业务方法处理业务逻辑
 * 4)封装处理结果交给DispatcherServlet进行处理.
 */
@RestController //@Controller+@ResponseBody = @RestController
public class SysNoticeController { //这里写的类又称之为handler
    @Autowired
    private SysNoticeService sysNoticeService;

    /**添加数据
     * @PostMapping = @RequestMapping(value="/notice/doInsertSysNotice",method = RequestMethod.POST)
     * 假如方法参数使用了@RequestBody描述,客户端数据的提交要求json:
     * 1)请求方式:post
     * 2)请求Content-Type设计:application/json
     * 3)请求数据格式{"key1":"v1","key2":2,....}
     * 
     *结果封装为JsonResult,规范化
     */
    @PostMapping("/notice/doInsertSysNotice")
    public JsonResult doInsertSysNotice(@RequestBody SysNotice sysNotice){
        sysNoticeService.insertSysNotice(sysNotice);
        return new JsonResult("insert ok");
    }
    /**删除数据
    *rest风格url(软件架构编码风格),允许在url中基于{}方式定义变量
    *rest风格应用目的:让url的设计更加通用和简单
    *访问url: http://ip:port/notice/doDeleteSysNotice/14,15
    *方法参数的值假如来自url中{var}变量的值,则需要使用@PathVariable注解对参数进行描述*/
    @DeleteMapping("/notice/doDeleteSysNotice/{ids}")
    public JsonResult doDeleteSysNotice(@PathVariable Long... ids){
        int count = sysNoticeService.deleteSysNotice(ids);
        if (count == 0){
            throw new RuntimeException("记录可能不存在");
        }
        return new JsonResult("delete ok");
    }

    /** 更新数据
     *通过对象传入参数
     */
    @PutMapping("/notice/doUpdateSysNotice")
    public JsonResult doUpdateSysNotice(SysNotice sysNotice){
        sysNoticeService.updateSysNotice(sysNotice);
        return new JsonResult("update ok");
    }

    /**基于id查询Sysnotice对象
    *添加@RequestParam("idd")以后,客户端地址参数从 id=14 变成 idd=14
    */
    @GetMapping("/notice/doSelectBySysNoticeId")
    public JsonResult doSelectBySysNoticeId(@RequestParam("idd") Long id){
        return new JsonResult(sysNoticeService.selectBySysNoticeId(id));
    }

    /**基于条件删除数据
    *方法会由DispatcherServlet (controller)对象通过反射进行调用
    *dispatcherServlet拿到请求中参数时会将参数注入给反射调用的方法参数
    *其它写法: @RequestMapping(value="/notice/doFindNotices",method = RequestMethod.GET)
    */
    @GetMapping("/notice/doSelectBySysNotice")
    public JsonResult doSelectBySysNotice(SysNotice sysNotice){
        return new JsonResult(sysNoticeService.selectBySysNotice(sysNotice));
    }
}
/**
 * 请求响应处理
 * 请求数据:
 * 1)请求url的定义(普通风格url,rest风格url)
 * 2)请求方式的设计 (@GetMapping,@PostMapping,@DeleteMapping,@PutMapping,@RequestMapping)
 * 3)请求方法参数类型设计(直接量,pojo对象)
 * 4)请求方法参数修饰(@PathVariable->从url中取数据,@RequestBody-告诉服务端接收json数据,@RequestParam-对传统请求参数进行约束)
 * 响应数据
 * 1)响应标准设计
 * 2)响应数据转换(json格式数据)
 * 3)统一异常的处理(?)
 */

11.web全局异常处理类

image.png

  • 在handler出现的异常,假如不进行处理,那么就会返回给它的调用者DispatcherServlet处理,DispatcherServlet会找被注解@RestControllerAdvice修饰的全局处理类来处理,被@ExceptionHandler修饰的异常处理方法只能处理自己的异常类型或者自己子类的异常类型

    package com.cy.pj.sys.web.exception;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    /**
    * 此注解描述的类为全局异常处理类
    * 从控制层传来的异常会经过前端处理器,前端处理器找被@RestControllerAdvice修饰的全局异常处理类来处理
    * 传过来的异常类型是@ExceptionHandler注解定义的异常类型(此处为RuntimeException)或者它的子异常类型时
    * 才可以使用注解@ExceptionHandler所修饰的方法进行处理
    */
    @RestControllerAdvice
    public class GlobalExceptionHandler {
      private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
      /**@ExceptionHandler注解描述的方法为异常处理方法,
       * 注解中定义的异常类型为方法可以处理的异常类型.*/
      @ExceptionHandler(RuntimeException.class)
      public JsonResult doHandleRuntimeException(RuntimeException e){
          e.printStackTrace(); //打印异常信息到控制台
          log.error("exception msg is {}"+e.getMessage());
          return new JsonResult(e);
      }
    }
    

    12.拦截器的应用

    image.png

  • 对handler里的方法请求进行限制

  • 图中步骤2就进行了到达hanler之前的请求拦截

image.png

  • 多个拦截器组成拦截器链,采用循环方式遍历拦截

  • web. interceptor

    • TimeAccessInterceptor
      • 拦截具体事项:设置访问时间 ```java package com.cy.pj.sys.web.interceptor;

import lombok.extern.slf4j.Slf4j;

/**

  • 定义spring web 模块中的拦截器,通过此拦截器对handler中某些方法的
  • 进行时间访问限制。 / @Slf4j //lombok会在当前类编译成class文件时,自动在类文件中添加一个log对象 public class TimeAccessInterceptor implements HandlerInterceptor { / private static final Logger log=

              LoggerFactory.getLogger(TimeAccessInterceptor.class); */
    

    /**preHandle方法会在目标handler方法执行之前进行访问拦截

    • 方法返回值为true时表示请求放行,false表示请求到此结束,
    • 不再去执行handler中的方法
    • */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { LocalTime now = LocalTime.now(); //JDK8中的时间对象 int hour = now.getHour(); //获取当前时间对应小时 //System.out.println(“hour=”+hour); log.info(“hour=”+hour); if(hour<=8 || hour>=22){

       throw new RuntimeException("请在8-22点进行访问");
      

      } return true; }

      //测试方法参数,理解方法中参数含义 private void testRequestInfo(HttpServletRequest request, HttpServletResponse response, Object handler){ //获取请求url,地址栏的次地址 String uri = request.getRequestURI(); System.out.println(“request.uri=”+uri);

      //获取请求中的参数(客户端向服务端发送请求时所有参数都会封装到ParameterMap对象) Map map = request.getParameterMap(); //获取请求中的参数 System.out.println(“request.param.map.keys=”+map.keySet());

      //获取封装了目标handler(@Controller)和method信息的HandlerMethod对象 HandlerMethod handlerMethod = (HandlerMethod) handler; //获取了控制层handler对应的方法对象,方法对象包含方法全部信息 //访问权限范围, 方法的完整返回类型,方法的完整路径,方法的参数完整类型 Method method = handlerMethod.getMethod(); System.out.println(“method.name->”+method.getName()); System.out.println(“==preHandle==”); } } ```

  • web.config
    • SpringWebConfig
      • 注册拦截,设置拦截路径,拦截哪些方法 ```java package com.cy.pj.sys.web.config;

@Configuration //此注解为spring中的一个配置类bean对象 public class SpringWebConfig implements WebMvcConfigurer { /注册拦截器,并且设置要拦截的路径,此方法会在项目启动时就会调用*/ @Override public void addInterceptors(InterceptorRegistry registry) { //注册拦截器,并且设置要拦截的路径 //1、注册拦截器(将拦截器添加到spring容器) registry.addInterceptor(new TimeAccessInterceptor()) //2、设置要拦截的url //.addPathPatterns(“/notice/“); //拦截所有 .addPathPatterns(“/notice/doSelectBySysNotice”,”/notice/doDeleteSysNotice/*”); } }


<a name="JuNMP"></a>
#### 13.项目测试

- 客户端可以进行插入操作,不对type类型赋值,进行异常测试,或者删除操作,输入不存在的id测试异常
- 客户端输入对应的url,即可调用相应的controller方法,运行
<a name="GMxVy"></a>
#### 日志级别

- 日志的规范是slf4j,好的实现类有LogBack等
- 日志等级
   - trace<debug<info<warn<error
- 当我们在springboot配置文件中指定的日志级别为info时,会显示等级大于等于info的相关信息(info,warn,error)
```java
package com.cy.pj.sys.service;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class LogTests {
    //通过日志工厂来获得日志对象,降低了耦合,单个实现类的崩溃不会导致这个代码的崩溃
    @Autowired
    private static final Logger log = LoggerFactory.getLogger(LogTests.class);
    //level: trace<debug<info<warn<error
    //当我们在springboot配置文件中指定的日志级别为info时,会显示info,warn,error相关信息
    @Test
    void testLevel(){
        log.trace("log.level.trace");
        log.debug("log.level.debug");
        log.info("log.level.info");
        log.warn("log.level.warn");
        log.error("log.level.error");
    }
}

03-系统公告管理(技术点框架整合).pdf