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中动态拦截控制器方法的执行

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

拦截器与过滤器区别:

  1. 归属不同:Filter属于Servlet技术,Interecptor属于SpringMVC技术

  2. 拦截内容不同: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:与配置顺序相反,可能不运行

相关推荐
hashiqimiya15 小时前
后端springboot的接收前端发来的数据反序列化原理
java
cat三三16 小时前
java之异常
java·开发语言
浙江第二深情16 小时前
前端性能优化终极指南
java·maven
养乐多072216 小时前
【Java】IO流
java
俊男无期16 小时前
超效率工作法
java·前端·数据库
中国胖子风清扬16 小时前
SpringAI和 Langchain4j等 AI 框架之间的差异和开发经验
java·数据库·人工智能·spring boot·spring cloud·ai·langchain
月明长歌16 小时前
【码道初阶】牛客TSINGK110:二叉树遍历(较难)如何根据“扩展先序遍历”构建二叉树?
java·数据结构·算法
用户21903265273516 小时前
Spring Boot + Redis 注解极简教程:5分钟搞定CRUD操作
java·后端
Alice16 小时前
linux scripts
java·linux·服务器
Filotimo_17 小时前
Spring Data JPA 方法名查询特性的使用
java·开发语言·windows