目录
spring整合mybatis,使用Junit对service层做测试
1.表现层数据封装
前端拿到的数据
等一下,我们就说假如啊?假如,我们增删改,后端不就是只给一个true或者false吗?但是查询是给一个封装好的json你对象,前端按照你的格式,去遍历数据,是不是格式种类多?所以,统一封装一个格式,对象,属性名data,
等一下,拿到code编码,根据编码号,判断返回错误或者失败,当然这是为了查询准备的,增删改bool值,完全没必要,但还是要封装到一起。meg错误信息,是为了查询返回的,表示查询失败。但还是要封装到一起的。
就是返回前端的数据,要统一一个格式。
包结构
只是建议这样写
Result.java
public class Result {
private Object data; // 对象
private Integer code; // 请求成功或失败编码
private String msg; // 返回的特殊信息
public Result() {
}
public Result(Integer code,Object data) {
this.data = data;
this.code = code;
}
public Result(Integer code, Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
我们是不是需要什么编码?来表明成功还是失败?
Code.java
编码随意,最好5为,结尾0表示失败,1表示成功。
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;
// 出异常的编码
public static final Integer SYSTEM_ERR = 50001;
public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
public static final Integer SYSTEM_UNKNOW_ERR = 59999;
public static final Integer BUSINESS_ERR = 60002;
public static final Integer EXCEPTION_ERR = 11111;
}
总结
我们要将数据封装成一个具有data(数据),code(成功、错误编码),message(特殊消息),的一个对象(属性可扩展多个)的对象,返回给前端。
自定义一个Code类,封装错误成功编码。
2.项目异常
异常处理器,如果后端服务器出现上述异常,我们要让他跟那些正常代码返回给前端的数据格式一致,所以也要设置一个异常处理器,来处理。
ProjectExceptionAdvice.java
//@RestControllerAdvice 用于标识当前类为REST风格对应的异常处理器
//@ControllerAdvice 用于表示当前类为异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//@ExceptionHandler用于拦截当前处理器类对应的异常类型
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
项目异常分类
假如说,用户访问不同的网址,导致匹配不到正确的路径,然后产生异常,
区分异常种类,一般也就这两个常用的,业务异常(BusinessException),系统异常(SystemException),将我们捕获的异常,转换成我们自己定义的异常,抛出被SPringMvc捕获。
下面
BusinessException.java
//自定义异常处理器,用于封装异常信息,对异常进行分类
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public BusinessException(String message) {
super(message);
}
public BusinessException(Integer code,Throwable cause,String message) {
super(message, cause); // 我们不是继承异常,Throwable,是Exception的父
this.code = code;
}
public BusinessException( Integer code,String message) {
super(message); // message,就是异常抛出的消息
this.code = code;
}
}
模拟异常抛出:
将捕获java的异常转换成自定义异常,我觉得以后这个话,有可能也封装成一条常量吧,毕竟以后异常处理器是为了保证返回给前端的数据格式统一,就算出异常也是如此格式。但是自定义异常。感觉无所谓。
try{
int i = 1/0;
}catch (Exception e){
throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);
}
ProjectExceptionAdvice.java
//@RestControllerAdvice 用于标识当前类为REST风格对应的异常处理器
//@ControllerAdvice 用于表示当前类为异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
//1.捕获系统异常
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(ex.getCode(),null,ex.getMessage());
}
// 2.捕获业务异常
@ExceptionHandler(BusinessException.class)
public Result doBusinessException(BusinessException ex){
return new Result(ex.getCode(),null,ex.getMessage());
}
//3.捕获其他异常
@ExceptionHandler(Exception.class)
public Result doOtherException(Exception ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
总结
AOP小结:
说一下,我们不是学aop,不是有个环绕通知吗?他能能够拿到并原对象,并调用他。
我们可以用环绕通知,给所有方法,绑定。捕获异常,并封装成自定义异常抛出。
异常处理器作用:为了保证服务器出异常时,向前端返回的数据统一数据格式。
1.自定义异常 2.系统抛出异常 3.异常处理器捕获异常()
3.放行静态资源
// 这个配置类,支持spring的扩展功能,当然也可以把他放在springConfig里,这样
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
}
针对添加和删除等操作的细节描写.....
提交表单?
我们点击提交之后,按照之前?特殊消息?状态码?成功?失败?将特殊消息拿过来?
编辑表单?
我们点击编辑之后,是不是要有这个数据,反显到表单里,那是不要根据id查询数据。
然后,将数据填充到表单里。然后,编辑数据,将新的数据提交给后端。
4.拦截器
跟过滤器,差不多只不过只是针对SpringMvc能镜像映射的路径来说,看来学到的SpringMvc中,mvc扩展功能,也就拦截器有点用,毕竟是针对动态逻辑的。
ProjectInterceptor.java
配置拦截器
1.定义拦截器
@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
@Override
// 原始操作被拦截之前,执行的代码
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
// if return false,代表终止你原始操作。,也就是真真整的拦截你原始操作的执行。
}
@Override
// 原始操作被拦截后执行的代码
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postman......");
}
@Override
//拦截之后执行的代码
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("执行方法后调用的内容......");
}
}
2.配置拦截器被拦截那个路径,你这个配置类,被其他扫描上,也相当于连接在一起了,@CompentScan扫描之后,一个能和配置类和其他配置类能连接在一起,另外像是被@Service等标签,表上的不就是相当于new Bean()操作,?但前提是交给spring来管理也就是被springConfig配置文件扫描上。
SpringMvcSupport.java
@Configuration
// webMvc的扩展功能,
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 这个以后前后端分离就没用了...........
// 拦截静态资源
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
}
}
这tm就是个代理,在controller中实际又加上一个代理对象,可以参考aop的环绕通知来理解。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String contentType = request.getHeader("Content-Type");
HandlerMethod hm = (HandlerMethod)handler;
Method method = hm.getMethod();
// 怎么理解封装这个概念,有些时候,按照参数输出类,也不一定是它本身的类,看他真正的类型,getClass(),毕竟每个对象有JVM给我们创建,但是真实数据类型你不知道。任何一个良好简装的程序私有属性,都是对应的get ,set方法。
// Spring的半壁江山,IOC, = spring帮你new bean() ; AOP,通过spring 帮我们创建代理对象,来调用对应的方法。
// springMvc,
System.out.println("preHandle...222");
return false;
}
拦截器链
其实拦截器链,我为什么想的是vip呢?
总结:除了拦截器的SSM项目,搭建具体流程。
1.先变成Web项目,导入pom.xml坐标,(就算记住,考虑版本不匹配问题,建议写个博客,把基本框架需要坐标放进去)
2.建一个包架构,再建spring核心配置类,jdbc核心配置类,mybatis核心配置类,SpringMvc核心配置类,servlet核心配置类(tomcat,加载你这些关键配置文件),
3.一般就是做test测试之类的,做业务层的。(提示,可能出现的错误)
PS :发现了一个问题,我数据库设置表列的格式,跟前端要存入的数据,不满足我数据库的格式。他md,抛异常?
解决方法1:我通过aop,对前端的数据进行过滤格式化,保证正确性,其实挺傻逼的,前端也能过滤,只不过双重保险。
Cause: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'sex' at row 1
// 你想存入的数据太长了。
4.就是对controller层进行完善了,一般我们创建controller层,因为要保证向前端传输的数据格式是一致的,建一个Rusult类,将data,code,message...属性封装进去,建一个Code类,封装成功错误编码,ExceptionAdvice 异常捕获通知类,@RestControllerAdvice ,ProInterceptor 拦截器类
怎么说呢?异常通知类,就是捕获向上抛的异常的,我们可以在其他层捕获(绑定一个aop),按照异常类型划分,抛出不同的我们自定义异常,然后被异常处理器捕获。