SpringMVC-Day2
基于RESRful页面数据交互
1.制作SpringMVC控制器,并通过PostMan测试接口功能
@RestController @RequestMapping("/books") public class BookController { @PostMapping public String save(@RequestBody Book book){ System.out.prinln("book save ==>" + book); return "{'module':'book save success'}"; } @GetMapping public List<Book> getAll(){ System.out.println("book getAll is runing ..."); List<Book> bookList = new ArrayList<Book>(); Book book1 = new Book(); book1.setType("计算机"); book1.setName("SpringMVC入门教程") book1.setDescription("小试牛刀") bookList.add(book1); //模拟数据... return bookList; } }
2.设置对静态资源的访问放行
//放行非springmvc的请求 @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { // 当访问/pages/???时,走/pages目录下的内容 registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); } }
3.前端页面通过异步提交访问后台控制器
//添加 saveBook(){ axios.post("/books",this.formData).then((res)=>{ }); }, //主页列表查询 getAll(){ axios.get("/books").then((res)=>{ this.dataList = res.data; }); };
5.SSM整合
1.整合配置
JdbcConfig
public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
MybatisConfig
public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.zkw.domain"); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc = new MapperScannerConfigurer(); msc.setBasePackage("com.zkw.dao"); return msc; } }
ServletConfig
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
SpringConfig
@Configuration @ComponentScan({"com.zkw.service"}) @PropertySource("jdbc.properties") @Import({JdbcConfig.class, MybatisConfig.class}) public class SpringConfig { }
SpringMvcConfig
@Configuration @ComponentScan("com.zkw.controller") @EnableWebMvc public class SpringMvcConfig { }
2.功能模块开发
BookController
@RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public boolean save(@RequestBody Book book) { return bookService.save(book); } @DeleteMapping("/{id}") public boolean delete(@PathVariable Integer id) { return bookService.delete(id); } @PutMapping public boolean update(@RequestBody Book book) { return bookService.update(book); } @GetMapping("/{id}") public Book getById(@PathVariable Integer id) { return bookService.getById(id); } @GetMapping public List<Book> getAll() { return bookService.getAll(); } }
BookService
public interface BookService { public boolean save(Book book); public boolean delete(Integer id); public boolean update(Book book); public Book getById(Integer id); public List<Book> getAll(); }
BookServiceImpl
@Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; @Override public boolean save(Book book) { bookDao.save(book); return true; } @Override public boolean delete(Integer id) { bookDao.delete(id); return true; } @Override public boolean update(Book book) { bookDao.update(book); return true; } @Override public Book getById(Integer id) { return bookDao.getById(id); } @Override public List<Book> getAll() { return bookDao.getAll(); } }
BookDao
public interface BookDao { @Insert("insert into tbl_book values(null,#{type},#{name},#{description})") public void save(Book book); @Update("update tbl_book set type=#{type},name=#{name},description=#{description} where id=#{id}") public void update(Book book); @Delete("delete from tbl_book where id = #{id}") public void delete(Integer id); @Select("select * from tbl_book where id = #{id}") public Book getById(Integer id); @Select("select * from tbl_book") public List<Book> getAll(); }
Book
public class Book { private Integer id; private String type; private String name; private String description; @Override public String toString() { return "Book{" + "id=" + id + ", type='" + type + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
事务处理
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager ds = new DataSourceTransactionManager(); ds.setDataSource(dataSource); return ds; }
3.接口测试
BookServiceTest
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetById(){ Book book =bookService.getById(1); System.out.println(book); } @Test public void testGetAll(){ List<Book> all =bookService.getAll(); System.out.println(all); } }
再用PostMan去测试增删改查功能是否成功
6.表现层和前端数据传输协议
设置统一数据返回结果类
public class Result { private Object data; private Integer code; private String msg; }
通过code可以得知,是增删改查何种操作,最后的数字,1代表成功,0代表失败
-
20031 -> 增删改
-
20041 -> 查询
编写Code
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; }
修改BookController
@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); } @DeleteMapping("/{id}") public Result delete(@PathVariable Integer id) { boolean flag = bookService.delete(id); return new Result(flag ? Code.DELETE_OK:Code.DELETE_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); } @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); } }
7.异常处理器
由于各个层级均会出现异常,所以将所有的异常均抛出到表现层处理
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception e){ System.out.println("已发现异常"); return new Result(666,null,"已发现异常"); } }
通过@RestControllerAdvice声明其为一个异常处理器
再通过@ExceptionHandler来定义处理哪一种异常
8.项目异常处理方案
-
业务异常(BusinessException)
-
发送对应消息传递给用户,提醒规范操作
-
-
系统异常(SystemException)
-
发送固定信息传递给用户,安抚用户
-
发送特定消息给运维人员,提醒维护
-
记录日志
-
-
其他异常(Exception)
-
发送固定消息传递给客户,安抚客户
-
发送特定消息给编程人员,提醒维护(纳入预期范围)
-
记录日志
-
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException e){ //记录日志 //发送消息给运维 //发送邮件给开发人员 return new Result(e.getCode(),null,e.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException e){ //记录日志 //发送消息给运维 //发送邮件给开发人员,ex对象发给开发人员 return new Result(e.getCode(),null,e.getMessage()); } @ExceptionHandler(Exception.class) public Result doException(Exception e){ System.out.println("已发现异常"); return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试"); } }
要根据对应的异常,设定相应的异常编码
自定义项目级系统异常
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; } }
9.前后台协议联调
method: { //列表功能 getAll() { //发送ajax请求 axios.get("/books").then((res)=>{ this.dataList = res.data.data; }); }, //重置表单 resetForm(){ this.formData = {}; }, //添加 handleAdd(){ //发送ajax请求 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); //row.id 查询条件 //查询数据,根据id if(res.data.code == 20041){ //展示弹层,加载数据 this.formData = res.data.data; this.diagloFormVisible4Edit = true; }else{ this.$message.error("res.data.msg"); } }); }, //编辑 handleEdit(){ //发送ajax请求 axios.pup("/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("删除失败"); } }); }).catch(()=>{ //3.取消删除操作 this.$message.info("取消删除操作"); }).finally(()=>{ this.getAll(); }); } } })
10.拦截器
拦截器概念:是一种动态拦截方法调用的机制,再SpringMVC中动态拦截控制器方法的执行
作用:在指定的方法调用前后执行预先设定的代码;阻止原始方法的执行
拦截器与过滤器区别:
-
归属不同:Filter属于Servlet技术,Interecptor属于SpringMVC技术
-
拦截内容不同:Filter对所有访问进行增强,Interecptor仅针对SpringMVC的访问进行增强
拦截器入门案例:
1.声明拦截器的bean,并实现HandlerInterceptor接口
@Component public class ProjectInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle..."); return true; //false可终止原始操作 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
2.定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); } }
拦截器配置
拦截器可以配多个,形成拦截链
-
preHandle:与配置顺序相同,必定运行
-
postHandle:与配置顺序相反,可能不运行
-
afterCompletion:与配置顺序相反,可能不运行