系列文章目录
第一章、SSM整合
第二章、表现数据封装
第三章、异常处理器
第四章、项目异常处理方案
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
Spring整合MyBatis、SpringMVC的实现,并实现简单的处理异常
提示:以下是本篇文章正文内容,下面案例可供参考
一、SSM整合流程
1、创建web工程
- 导入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
</dependencies>
2、SSM整合
- Spring
- SpringConfig
@Configuration
@ComponentScan("com.itheima.service")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
-
Mybatis
- MybatisConfig
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.itheima.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.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.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@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
jdbc.username=root
jdbc.password=root
- SpringMVC
- ServletConfig
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- SpringMVCConfig
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMVCConfig {
}
3、功能模块
- 表与实体类
public class book {
private Integer id;
private String type;
private String name;
private String description;
//自动生成get/set方法和toSpring方法
}
-数据层标准开发
public interface BookDao {
@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}")
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();
}
- 业务层标准开发
@Transactional
public interface BookService {
public boolean save(Book book);
public boolean update(Book book);
public boolean delete(Integer id);
public book getById(Integer id);
public List<Book> getAll();
}
@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);
return true;
}
public book getById(Integer id) {
return bookDao.getById(id);
}
public List<Book> getAll() {
return bookDao.getAll();
}
}
- 测试接口-----业务层接口测试(整合Junit)
@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);
}
}
- 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();
}
}
- 表现层接口测试(PostMan)
二、表现数据封装
1. 表现层与前端数据传输协议的定义
-
前端接收数据格式-创建结果模型,封装数据到data属性中
-
前端接收数据格式-封装操作结果到code属性中
-
前端接收数据格式-封装特殊消息到message(msg)属性中
2. 表现层与前端数据传输协议的实现 -
编写Result类 设置统一数据返回结果类
/**
* 根据情况设定合理的Result
*/
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;
}
}
注意:Result类中的字段并不是固定的,可以根据需要自行增减,提供若干个构造方法,方便操作
- 编写Code类 设置统一数据返回结果编码
public class Code {
// 尾数为1表示成功 0表示失败
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;
}
注意:Code类的常量设计也不是固定的,可以根据需要自行增减,
例如将查询再进行细分为GET_OK,GET_ALL_OK,GET_PAGE_OK
- 修改表现层controller代码,实现前端数据传输协议
@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);
}
}
三、异常处理器
出现异常现象的常见位置与常见诱因如下:
- 框架内部抛出的异常:因使用不合规导致
- 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
- 业务层抛出的异常:因业务逻辑书写错误导致
- 表现层抛出的异常:因数据收集,校验等规则导致(例如:不匹配的数据类型间导致异常)
- 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)
两个注解:
- @RestControllerAdvice:在类上标识,表示标识的类做异常处理工作
- @ExceptionHandler:在方法上标识,表示异常处理器
注意:需要在SpringMVCConfig中配置 让其扫描到此注解
四、项目异常处理方案
- 业务异常(BusinessException)
- 发送对应消息传递给用户,提醒规范操作
- 系统异常(SystemException)
- 发送固定消息传递给用户,安抚用户
- 其他异常(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;
}
- 自定义项目业务异常
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;
}
}
- 自定义统异常编码(补充在Code类中)
public static final Integer SYSTEM_ERR=50001; //系统异常结果编码
public static final Integer SYSTEM_TIEMOUT_ERR=50002; //系统超时异常结果编码
public static final Integer SYSTEM_UNKNOW_ERR=59999; //系统未知异常结果编码
public static final Integer BUSINESS_ERR=60002; //业务异常结果编码
- 自定义异常并包装异常(触发自定义异常)
- 在实现业务层中模拟异常(BookServiceImpl)
public book getById(Integer id) {
//模拟异常
if(id<0){
throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐心!");
}
//将可能出现的异常进行包装,转换成自定义异常
try {
int i=1/0;
}catch (Exception e){
throw new SystemException(Code.SYSTEM_TIEMOUT_ERR,"服务器启动超时,请稍后重试!");
}
return bookDao.getById(id);
}
- 拦截并处理异常
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(SystemException.class)
public Result doSystemException(SystemException 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){
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍联系管理员!");
}
}