SpringMVC
1.SSM整合
2.统一结果封装
- 为了封装返回的结果数据:创建结果模型类,封装数据到data属性中
- 为了封装返回的数据是何种操作及是否操作成功:封装操作结果到code属性中
- 操作失败后为了封装返回的错误信息:封装特殊消息到message(msg)属性中
public class Result{
private Object data;
private Integer code;
private String msg;
}
注意:Result类名及类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作。
表现层与前端数据传输协议实现
package com.itheima.controller;
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;
}
}
package com.itheima.controller;
//状态码
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;
}
package com.itheima.controller;
import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(@RequestBody Book book) {
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@PutMapping
public Result update(@RequestBody Book book) {
boolean flag = bookService.update(book);
return new Result(flag ? Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
boolean flag = bookService.delete(id);
return new Result(flag ? Code.DELETE_OK:Code.DELETE_ERR,flag);
}
@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);
}
@GetMapping
public Result getAll() {
List<Book> bookList = bookService.getAll();
Integer code = bookList != null ? Code.GET_OK:Code.GET_ERR;
String msg = bookList != null ? "":"数据查询失败请重试";
return new Result(code,bookList,msg);
}
}
3.统一异常处理
异常的种类及出现异常的原因:
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
- 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
所有的异常均抛出到表现层进行处理
package com.itheima.controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result doException(Exception ex){
System.out.println("抓住异常了!");
return new Result(666,null,"嘿嘿,异常你哪里跑!");
}
}
项目异常处理方案
- 业务异常(BusinessException)
发送对应消息传递给用户,提醒规范操作 - 系统异常(SystemException)
发送固定消息传递给用户,安抚用户
发送特定消息给运维人员,提醒维护
记录日志 - 其他异常(Exception)
发送固定消息传递给用户,安抚用户
发送特定消息给运维人员,提醒维护
记录日志
package com.itheima.exception;
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, String message) {
super(message);
this.code = code;
}
public SystemException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
package com.itheima.exception;
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, String message) {
super(message);
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
package com.itheima.controller;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException ex){
//记录日志
//发送消息给运维
//发送邮件给开发人员,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){
//记录日志
//发送消息给运维
//发送邮件给开发人员,ex对象发送给开发人员
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
}
}
public Book getById(Integer id) {
//模拟业务异常,包装成自定义异常
if(id == 1){
throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的 耐性!");
}
//模拟系统异常,将可能出现的异常进行包装,转换成自定义异常
try {
int i =1/0;
} catch (ArithmeticException e) {
throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重 试!",e);
}
return bookDao.getById(id);
}
4.前后台协议联调
列表功能
//列表
getAll() {
axios.get("/books").then((res)=>{
this.dataList = res.data.data;
});
},
添加功能
//弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();
},
//重置表单
resetForm() {
this.formData = {};
},
//添加
handleAdd () {
axios.post("/books",this.formData).then((res)=>{
//如果操作成功关闭弹层,显示数据
if (res.data.code == 20011){
this.dialogFormVisible = false;
this.$message.success("添加成功");
}else if (res.data.code == 20010){
this.$message.error("添加失败");
}else {
this.$message.error(res.data.msg);
}
}).finally(()=>{
this.getAll();
});
},
修改功能
handleUpdate(row) {
//console.log(row);
//查询数据,根据id
axios.get("/books/"+row.id).then((res)=>{
if (res.data.code == 20041) {
//展示弹层,加载数据
this.formData = res.data.data;
this.dialogFormVisible4Edit = true;
}else {
this.$message.error(res.data.msg);
}
});
},
//编辑
handleEdit() {
axios.put("/books",this.formData).then((res)=>{
//如果操作成功关闭弹层,显示数据
if (res.data.code == 20031){
this.dialogFormVisible4Edit = false;
this.$message.success("修改成功");
}else if (res.data.code == 20030){
this.$message.error("修改失败");
}else {
this.$message.error(res.data.msg);
}
}).finally(()=>{
this.getAll();
});
},
删除功能
// 删除
handleDelete(row) {
//1.弹出提示框
this.$confirm("此操作永久删除当前数据,是否继续?","提示",{
type: 'info'
}).then(()=>{
//2.做删除业务
axios.delete("/books/"+row.id).then((res)=>{
if (res.data.code == 20021) {
this.$message.success("删除成功");
}else {
this.$message.error("删除失败");
}
}).finally(()=>{
this.getAll();
});
}).cache(()=>{
//3.取消删除
this.$message.info("取消删除操作");
});
}
}
})
拦截器
拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
package com.itheima.controller.interceptpr;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class ProjectInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("perHandle...");
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("afterHandle...");
}
}
package com.itheima.config;
import com.itheima.controller.interceptpr.ProjectInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
}
}
简化:
@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer{
@Autowired
private ProjectInterceptor projectInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}