目录
ssm框架整合
第一步:指定打包方式和导入所需要的依赖
打包方法:war
springMVC所需依赖
解析json依赖
mybatis依赖
数据库驱动依赖
druid数据源依赖
junit依赖
第二步:导入tomcat插件
第三步:编写配置类
SpringConfig配置类
JdbcConfig配置类
MybatisConfig配置类
SpringMvcConfig配置类
ServletContainerInitConfig配置类
注意点:
第四步:准备数据库并写对应的pojo类型
第五步:编写dao层
第六步:编写service层
第七步:编写controller层
第八步:封装数据
响应码类
封装结果类
修改后的Controller
报错:这里我使用postman测试时,报错 No converter for [class com.hhh.pojo.vo.Result] with preset Content-Type 'null'
异常处理器
业务异常
系统异常
异常处理器
拦截器
如何定义拦截器
1.定义一个拦截器类,并实现HandlerInterceptor
2.配置加载拦截器
3.让SpringMVC加载此配置类
拦截器链
ssm框架整合
先自己创建Maven工程
第一步:指定打包方式和导入所需要的依赖
打包方法:war
<groupId>com.hhh</groupId><artifactId>spring_day7_ssm2</artifactId><version>1.0-SNAPSHOT</version> <!-- 使用war方式进行打包--><packaging>war</packaging>
springMVC所需依赖
<!-- springMVC依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency>
解析json依赖
<!-- json解析--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency>
mybatis依赖
<!-- mybatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.1.0</version></dependency>
数据库驱动依赖
<!-- 数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.13</version></dependency>
druid数据源依赖
<!-- druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency>
junit依赖
<!-- junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.10.RELEASE</version></dependency>
第二步:导入tomcat插件
<build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><!-- 指定端口 --><port>8080</port><!-- 请求路径 --><path>/</path><uriEncoding>utf-8</uriEncoding><!-- <!–这个名称需要,在maven插件中显示应用名称–>--><!-- <server>tomcat7</server>--></configuration></plugin></plugins></build>
完整的pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hhh</groupId><artifactId>spring_day7_ssm2</artifactId><version>1.0-SNAPSHOT</version> <!-- 使用war方式进行打包--><packaging>war</packaging><properties><maven.compiler.source>21</maven.compiler.source><maven.compiler.target>21</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies> <!-- springMVC依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency> <!-- json解析--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency> <!-- mybatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.1.0</version></dependency> <!-- 数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.13</version></dependency> <!-- druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency> <!-- junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.2.10.RELEASE</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><!-- 指定端口 --><port>8080</port><!-- 请求路径 --><path>/</path><uriEncoding>utf-8</uriEncoding><!-- <!–这个名称需要,在maven插件中显示应用名称–>--><!-- <server>tomcat7</server>--></configuration></plugin></plugins></build></project>
第三步:编写配置类
SpringConfig配置类
@Configuration @ComponentScan({"com.hhh.dao","com.hhh.service"}) @PropertySource("classpath:jdbc.properties")//导入外部文件 @Import({JdbcConfig.class, MybatisConfig.class})//加载外部配置类 @EnableTransactionManagement//开启事务功能 public class SpringConfig { }
JdbcConfig配置类
//管理第三方技术 这个类写数据源和事务处理器 public class JdbcConfig {@Value("${jdbc.driver}")private String driver;@Value("${jdbc.url}")private String url;@Value("${jdbc.username}")private String name;@Value("${jdbc.password}")private String password;@Beanpublic DataSource dataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setDriverClassName(driver);druidDataSource.setUrl(url);druidDataSource.setUsername(name);druidDataSource.setPassword(password);return druidDataSource;}@Beanpublic PlatformTransactionManager manager(DataSource dataSource){//spring会根据类型自动注入相同类型的beanDataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();dataSourceTransactionManager.setDataSource(dataSource);return dataSourceTransactionManager;} }
MybatisConfig配置类
public class MybatisConfig {@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);sqlSessionFactoryBean.setTypeAliasesPackage("com.hhh.pojo");//设置pojo类别名return sqlSessionFactoryBean;}@Beanpublic MapperScannerConfigurer mapperScannerConfigurer(){MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();mapperScannerConfigurer.setBasePackage("com.hhh.dao");//扫描dao层,并帮dao层的接口类创建代理对象beanreturn mapperScannerConfigurer;} }
SpringMvcConfig配置类
@Configuration @ComponentScan("com.hhh.controller") @EnableWebMvc//开启辅助功能 public class SpringMvcConfig { }
ServletContainerInitConfig配置类
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {//加载spring核心配置类@Overrideprotected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}//加载springMVC核心配置类@Overrideprotected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}//设置哪些请求路径交给springMVC管理@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}//设置post中文请求乱码@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();characterEncodingFilter.setEncoding("utf-8");return new Filter[]{characterEncodingFilter};} }
注意点:
SpringMvc核心配置类和Spring配置类不能互相扫描,假如@Import({JdbcConfig.class, MybatisConfig.class})多了com.hhh.config,就会报错
Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
编写完配置类之后我们先启动项目看看,会不会出错
注意:启动之前现在main目录下创建一个webapp目录
没有问题
第四步:准备数据库并写对应的pojo类型
public class Book {private Integer id;private String name;private String description;private Integer score;@Overridepublic String toString() {return "Book{" +"id=" + id +", name='" + name + '\'' +", description='" + description + '\'' +", score=" + score +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}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;}public Integer getScore() {return score;}public void setScore(Integer score) {this.score = score;}}
第五步:编写dao层
由于修改操作需要id和Book类对象,所以重新写一个pojo类
public class UpdateBook {Integer id;Book book;@Overridepublic String toString() {return "UpdateBook{" +"id=" + id +", book=" + book +'}';}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Book getBook() {return book;}public void setBook(Book book) {this.book = book;} }
//这里不用写@Repository注解,因为MybatisConfig会扫描这一个包下的所有接口类,并创建代理对象 public interface BookDao {//新增操作@Insert("insert into book(name, description, score) VALUE (#{name},#{description},#{score});")@Options(useGeneratedKeys = true,keyColumn = "id",keyProperty = "id")//设置主键回填Integer save(Book book);//查询全部@Select("select * from book;")List<Book> getAll();//查询某一个@Select("select * from book where id=#{id};")Book getById(Integer id);//删除@Delete("delete from book where id=#{id};")Integer deleteById(Integer id);//修改/*@Update("update book set name=#{book.name},description=#{book.description},score=#{book.score} where id=#{id};")Integer updateById(@Param("id") Integer id, @Param("book") Book book);*/@Update("update book set name=#{book.name},description=#{book.description},score=#{book.score} where id=#{id};")Integer updateById(UpdateBook u); }
第六步:编写service层
BookService接口
@Transactional//开启事务管理 public interface BookService {//新增操作Boolean save(Book book);//查询全部List<Book> getAll();//查询某一个Book getById(Integer id);//删除Boolean deleteById(Integer id);//修改Boolean updateById(UpdateBook updateBook); }
BookServiceImpl实现类
@Service public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Overridepublic Boolean save(Book book) {return bookDao.save(book)>0;//大于0为真}@Overridepublic List<Book> getAll() {return bookDao.getAll();}@Overridepublic Book getById(Integer id) {return bookDao.getById(id);}@Overridepublic Boolean deleteById(Integer id) {return bookDao.deleteById(id)>0;}@Overridepublic Boolean updateById(UpdateBook updateBook) {return bookDao.updateById(updateBook)>0;} }
测试一下
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class)//加载spring核心配置类 public class BookServiceTest {@Autowiredprivate BookService bookService;@Testpublic void testGetAll(){List<Book> list = bookService.getAll();System.out.println(list);}@Testpublic void testGetById(){Book book= bookService.getById(2);System.out.println(book);}@Testpublic void testSave(){Book book = new Book();book.setName("hh");book.setDescription("aa");book.setScore(90);Boolean aBoolean = bookService.save(book);System.out.println(aBoolean);//trueSystem.out.println("id="+book.getId());//11}@Testpublic void testUpdate(){Book book = new Book();book.setName("hhh");book.setDescription("aaa");book.setScore(70);UpdateBook updateBook = new UpdateBook();updateBook.setBook(book);updateBook.setId(9);Boolean b = bookService.updateById(updateBook);System.out.println(b);}@Testpublic void testDelete(){Boolean b = bookService.deleteById(11);System.out.println(b);} }
全部正确
第七步:编写controller层
/*@ResponseBody @Controller*/ @RestController @RequestMapping(value = "/books",produces = "text/html;charset=utf-8") public class BookController {@Autowiredprivate BookService bookService;@PostMappingpublic String save(@RequestBody Book book){//解析json对象Boolean b = bookService.save(book);return b?"保存成功":"保存失败";//return "保存成功";}@GetMappingpublic List<Book>getAll(){return bookService.getAll();}@GetMapping("/{id}")public Book getById(@PathVariable Integer id){//从路径中获取值return bookService.getById(id);}@PutMappingpublic String update(@RequestBody UpdateBook book){Boolean b = bookService.updateById(book);return b?"修改成功":"修改失败";}@DeleteMapping("/{id}")public String delete(@PathVariable Integer id){//从路径中获取值Boolean b = bookService.deleteById(id);return b?"删除成功":"删除失败";} }
使用postman测试
完全正确
第八步:封装数据
响应码类
public class Code {public static final Integer SAVE_OK=10010;public static final Integer UPDATE_OK=10020;public static final Integer DELETE_OK=10030;public static final Integer SELECT_OK=10040;public static final Integer SAVE_ERR=10011;public static final Integer UPDATE_ERR=10021;public static final Integer DELETE_ERR=10031;public static final Integer SELECT_ERR=10041;}
封装结果类
public class Result {private Integer code;//响应码private Object data;//响应数据private String msg;//响应信息,可有可无@Overridepublic String toString() {return "Result{" +"code=" + code +", data=" + data +", msg='" + msg + '\'' +'}';}public Result(Integer code, Object data, String msg) {this.code = code;this.data = data;this.msg = msg;}public Result(Integer code, Object data) {this.code = code;this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}
修改后的Controller
/*@ResponseBody
@Controller*/
@RestController
@RequestMapping(value = "/books",produces = "application/json;charset=utf-8")
public class BookController {@Autowiredprivate BookService bookService;@PostMappingpublic Result save(@RequestBody Book book){//解析json对象Boolean b = bookService.save(book);Integer code=b? Code.SAVE_OK:Code.SAVE_ERR;String msg=b?"新增成功":"新增失败";return new Result(code,b,msg);}@GetMappingpublic Result getAll(){List<Book> bookList = bookService.getAll();Integer code=bookList!=null?Code.SELECT_OK:Code.SELECT_ERR;String msg=bookList!=null?"查询成功":"查询失败";return new Result(code,bookList,msg);}@GetMapping("/{id}")public Result getById(@PathVariable Integer id){//从路径中获取值Book book = bookService.getById(id);Integer code=book!=null?Code.SELECT_OK:Code.SELECT_ERR;String msg=book!=null?"查询成功":"查询失败";return new Result(code,book,msg);}@PutMappingpublic Result update(@RequestBody UpdateBook book){Boolean b = bookService.updateById(book);Integer code=b? Code.UPDATE_OK:Code.UPDATE_ERR;String msg=b?"修改成功":"修改失败";return new Result(code,b,msg);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id){//从路径中获取值Boolean b = bookService.deleteById(id);Integer code=b? Code.DELETE_OK:Code.DELETE_ERR;String msg=b?"删除成功":"删除失败";return new Result(code,b,msg);}
}
报错:
这里我使用postman测试时,报错 No converter for [class com.hhh.pojo.vo.Result] with preset Content-Type 'null'
解决方法:
把@RequestMapping(value = "/books",produces = {"text/html;charset=UTF-8"})改成
@RequestMapping(value = "/books",produces = {"application/json;charset=UTF-8"})
异常处理器
我们可以把出现的异常封装成结果类,返回给前端
@RestControllerAdvice
//包好了@ResponseBody,@Component注解
public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class)//告诉spring这是处理异常的,负责处理Exception异常public Result doException(Exception e){return new Result(Code.ERR,null,"项目出错");}
}
还需要在Spring核心配置类中扫描到这个包,如果没有写,异常处理器就不会生效
@Configuration @ComponentScan({"com.hhh.dao","com.hhh.service","com.hhh.exception"}) @PropertySource("classpath:jdbc.properties")//导入外部文件 @Import({JdbcConfig.class, MybatisConfig.class})//加载外部配置类 @EnableTransactionManagement//开启事务功能 public class SpringConfig { }
我们随便写一个异常
结果:
我们可以把我们常见的异常分成
业务异常和系统出错异常
public static final Integer ERR=0;public static final Integer BUSINESS_ERR=20101;public static final Integer SYSTEM_ERR=20202;
先添加三个code编码
业务异常
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 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;}
}
异常处理器
@RestControllerAdvice
//包好了@ResponseBody,@Component注解
public class ProjectExceptionAdvice {@ExceptionHandler(BusinessException.class)//处理BusinessException异常public Result doBusinessException(BusinessException e){//接收程序传过来的异常return new Result(e.getCode(),null,e.getMessage());}@ExceptionHandler(SystemException.class)//处理SystemException异常public Result doSystemException(SystemException e){return new Result(e.getCode(),null,e.getMessage());}@ExceptionHandler(Exception.class)//告诉spring这是处理异常的,负责处理Exception异常public Result doException(Exception e){return new Result(Code.ERR,null,"项目出错");}
}
测试
成功:
拦截器
拦截器是一种动态拦截方法的机制
作用:
- 在指定方法调用前后执行预先设定后的代码
- 阻止原始方法的执行
如何定义拦截器
1.定义一个拦截器类,并实现HandlerInterceptor
@Component//交给容器管理
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle");//执行原方法之前return true;//返回true才能放行去访问controller}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandler");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion");}
}
spring核心配置类扫描该自定义的拦截器类,并生成bean
@Configuration
@ComponentScan({"com.hhh.dao","com.hhh.service","com.hhh.exception","com.hhh.interceptor"})
@PropertySource("classpath:jdbc.properties")//导入外部文件
@Import({JdbcConfig.class, MybatisConfig.class})//加载外部配置类
@EnableTransactionManagement//开启事务功能
public class SpringConfig {
}
2.配置加载拦截器
public class SpringWebSupport implements WebMvcConfigurer {@Autowiredprivate MyInterceptor myInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/books");//设置拦截的路径}
}
3.让SpringMVC加载此配置类
@Configuration
@ComponentScan("com.hhh.controller")
@EnableWebMvc//开启辅助功能
@Import(SpringWebSupport.class)
public class SpringMvcConfig {
}
结果:
拦截器链
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加的顺序为准
- 当拦截器中出现对原始拦截器的拦截(返回false),后面的拦截器均终止运行(后面的preHandler方法,所有postHandle方法和包括自身的afterCompletion方法都不执行)
- 当拦截器中断,仅运行配置在前面的拦截器的afterCompletion
添加其他的拦截器
加载这些拦截器
public class SpringWebSupport implements WebMvcConfigurer {@Autowiredprivate MyInterceptor myInterceptor;@Autowiredprivate MyInterceptor2 myInterceptor2;@Autowiredprivate MyInterceptor3 myInterceptor3;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myInterceptor).addPathPatterns("/books","/books/*");//设置拦截的路径registry.addInterceptor(myInterceptor2).addPathPatterns("/books","/books/*");registry.addInterceptor(myInterceptor3).addPathPatterns("/books","/books/*");}
}
执行的顺序就是加载的顺序
结果: