SSM基础整合
文章目录
- SSM基础整合
- @[toc]
- SSM基础整合
- SSM整合流程
- 表现层数据封装
- 设置统一数据返回结果类
- 定义code类
- 优化Controller
- 优化后的返还结果
- 异常处理器
- 异常处理
- 项目异常处理方案
- 项目异常分类
- 处理
文章目录
- SSM基础整合
- @[toc]
- SSM基础整合
- SSM整合流程
- 表现层数据封装
- 设置统一数据返回结果类
- 定义code类
- 优化Controller
- 优化后的返还结果
- 异常处理器
- 异常处理
- 项目异常处理方案
- 项目异常分类
- 处理
SSM基础整合
SSM整合流程
-
创建工程
-
SSM整合
-
Spring
-
SpringConfig
-
@Configuration @ComponentScan({"com.ityc.service"}) @PropertySource("classpath:jdbc.properties") @Import({JdbcConfig.class,MybatisConfig.class}) //事物 @EnableTransactionManagement public class SpringConfig { }
-
-
MyBatis
-
MyBatisConfig
public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); factoryBean.setTypeAliasesPackage("com.ityc.domain"); return factoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc= new MapperScannerConfigurer(); msc.setBasePackage("com.ityc.dao"); return msc; } }
-
JdbcConfig
public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.passworld}") private String passworld; //导入MySQL @Bean public DataSource DataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(passworld); return dataSource; } //事物 @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager ds = new DataSourceTransactionManager(); ds.setDataSource(dataSource); return ds; } }
-
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false jdbc.username=root jdbc.passworld=lyc
-
-
SpringMVC
-
SpringMvcConfig
@Configuration @ComponentScan("com.ityc.controller") @EnableWebMvc public class SpringMvcConfig { }
-
-
-
功能模块
-
表与实体类
package com.ityc.domain; public class Book { private Integer id; private String type; private String name; private String 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; } @Override public String toString() { return "Book{" + "id=" + id + ", type='" + type + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + '}'; } }
DROP TABLE IF EXISTS `tbl_book`; CREATE TABLE `tbl_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `tbl_book` VALUES (1, '计算机理论', 'Spring实战 第5版', 'Spring入门经典教程,深入理解Spring原理技术内幕'); INSERT INTO `tbl_book` VALUES (2, '计算机理论', 'Spring 5核心原理与30个类手写实战', '十年沉淀之作,手写Spring精华思想'); INSERT INTO `tbl_book` VALUES (3, '计算机理论', 'Spring 5 设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式'); INSERT INTO `tbl_book` VALUES (4, '计算机理论', 'Spring MVC+MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手'); INSERT INTO `tbl_book` VALUES (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握Java基础的读者'); INSERT INTO `tbl_book` VALUES (6, '计算机理论', 'Java核心技术 卷I 基础知识(原书第11版)', 'Core Java 第11版,Jolt大奖获奖作品,针对Java SE9、10、11全面更新'); INSERT INTO `tbl_book` VALUES (7, '计算机理论', '深入理解Java虚拟机', '5个维度全面剖析JVM,大厂面试知识点全覆盖'); INSERT INTO `tbl_book` VALUES (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉'); INSERT INTO `tbl_book` VALUES (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想和核心技术'); INSERT INTO `tbl_book` VALUES (10, '市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中'); INSERT INTO `tbl_book` VALUES (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍'); INSERT INTO `tbl_book` VALUES (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
-
dao(接口+自动代理)
package com.ityc.dao; import com.ityc.domain.Book; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import java.util.List; public interface BookDao { //@Insert("insert into tbl_book values (null,#{type},#{name},#{description})") @Insert("insert into tbl_book (type,name,description) values (#{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(); }
-
service(接口+实体类)
- 业务层接口测试(整合JUnit)
//接口 package com.ityc.service; import com.ityc.domain.Book; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.springframework.transaction.annotation.Transactional; import java.util.List; //开启事物 @Transactional public interface BookService { /** * 保存 * @param book * @return */ public boolean save(Book book); /** * 修改 * @param book * @return */ public boolean update(Book book); /** * 删除 根据id * @param id * @return */ public boolean delete(Integer id); /** * 按id查询 * @param id * @return */ public Book getById (Integer id); /** * 查询全部 * @return */ public List<Book> getALL(); }
//实现类 package com.ityc.service.impl; import com.ityc.dao.BookDao; import com.ityc.domain.Book; import com.ityc.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; public boolean save(Book book) { bookDao.save(book); return true; } public boolean update(Book book) { bookDao.update(book); return true; } public boolean delete(Integer id) { bookDao.delete(id); if(bookDao.getById(id)!=null){ bookDao.delete(id); return true; }else{ return false; } } public Book getById(Integer id) { return bookDao.getById(id); } public List<Book> getALL() { return bookDao.getALL(); } }
//测试 package com.ityc.service; import com.ityc.config.SpringConfig; import com.ityc.domain.Book; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; @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> bookAll = bookService.getALL(); System.out.println(bookAll); } }
-
conroller
-
表现层接口测试(PostMan)
package com.ityc.controller; import com.ityc.domain.Book; import com.ityc.service.BookService; import org.apache.ibatis.annotations.Delete; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; //基于Restful的controller开发 @RestController @RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @PostMapping public boolean save(@RequestBody Book book) { return bookService.save(book); } @PutMapping public boolean update(@RequestBody Book book) { return bookService.update(book); } @DeleteMapping({"/{id}"}) public boolean delete(@PathVariable Integer id) { return bookService.delete(id); } @GetMapping({"/{id}"}) public Book getById(@PathVariable Integer id) { return bookService.getById(id); } @GetMapping public List<Book> getALL() { return bookService.getALL(); } }
-
web配置类
package com.ityc.config; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer; import javax.servlet.Filter; public class SelectConfig extends AbstractAnnotationConfigDispatcherServletInitializer { //根配置 protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } //专门应对web请求的处理 //这里创建的容器对象与上方的容器对象不是同一个 protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } //POST提交乱码处理 @Override protected Filter[] getServletFilters() { CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("UTF-8"); return new Filter[]{filter}; } }
-
-
表现层数据封装
- 前端接收数据格式——创建结果模型类,封装数据到data属性中
- 前端接收数据格式——封装操作结果到code属性中
- 前端接收数据格式——封装特殊消息到message(msg)属性中
设置统一数据返回结果类
//Result类中的字段不是固定的,可以根据需要自行增减
//提供若干个构造方法,方便操作
package com.ityc.controller;
public class Result {
private Object data;
private Integer code;
private String msg;
public Result() {
}
public Result( Integer code,Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
public Result( Integer code,Object data) {
this.data = data;
this.code = code;
}
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类
package com.ityc.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;
}
优化Controller
package com.ityc.controller;
import com.ityc.domain.Book;
import com.ityc.service.BookService;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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);
String msg= flag?"删除成功":"数据为空,删除失败";
return new Result(flag?Code.DELETE_OK:Code.DELETE_ERR,flag,msg);
}
@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);
}
}
优化后的返还结果
注:
表现层数据封装,通过Result与Code类配合业业务,将数据整理成统一格式,反馈给前端页面,再由前端页面的书写人员进行统一解析。
异常处理器
异常处理
出现异常现象的常见位置与常见诱因如下
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛异常:因外部服务器故障导致(例:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致(例:遍历业务书写操作,导致索引异常)
- 表现层抛出的异常:因数据收集,校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨,不够健壮导致(例如:必要释放的连接长期未释放)
思考:各个层级均出现异常,异常处理代码书写在哪一层?
-
所有的异常均抛出到表现层进行处理
-
表现层处理异常,每个方法中单独书写,代码书写量巨大,且意义不强,如何解决?——AOP思想
-
SpringMVC为我们提供了异常处理器,来为我们集中的,统一的处理项目中的异常。
package com.ityc.controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestControllerAdvice; //Rest风格开发的控制器类做增强,本注解自带@ResponseBody注解与@Component注解,具备对应的功能 @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.ityc.exception; public class SystemException extends RuntimeException{ private Integer 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; } - public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } }
-
自定义项目业务级异常
package com.ityc.exception; public class BusinessException extends RuntimeException { private Integer 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; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public BusinessException(Integer code, String message, Throwable cause) { super(message, cause); this.code = code; } }
-
自定义异常编码(可持续补充)
package com.ityc.controller; public class Code { public static final Integer SYSTEM_ERR = 50001; public static final Integer SYSTEM_TIMEOUT_ERR = 50002; public static final Integer BUSINESS_ERR = 50003; public static final Integer SYSTEM_UNKNOW_ERR = 59999; }
-
触发自定义异常
public Book getById(Integer id) { if (id < 1){ throw new BusinessException(Code.BUSINESS_ERR,"警告,非法操作"); } return bookDao.getById(id); }
-
拦截并处理异常
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException sex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,sex对象发给开发人员 return new Result(sex.getCode(),null,sex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException bex){ //记录日志 //发送消息给运维 //发送邮件给开发人员 return new Result(bex.getCode(),null,bex.getMessage()); } //写一个方法用于处理异常 //设置拦截异常类型 @ExceptionHandler(Exception.class) public Result doException(Exception ex){ //记录日志 //发送消息给运维 //发送邮件给开发人员,sex对象发给开发人员 System.out.println("异常出来吧,别藏了"); return new Result(Code.SYSTEM_UNKNOW_ERR,null,"出现了位置异常,系统繁忙请稍后再试"); } }
-
异常处理器效果
注:
- 异常处理器
- 自定义异常
- 异常编码
- 自定义消息