目录
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; @Bean public DataSource dataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driver); druidDataSource.setUrl(url); druidDataSource.setUsername(name); druidDataSource.setPassword(password); return druidDataSource; } @Bean public PlatformTransactionManager manager(DataSource dataSource){//spring会根据类型自动注入相同类型的bean DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } }
MybatisConfig配置类
public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource); sqlSessionFactoryBean.setTypeAliasesPackage("com.hhh.pojo");//设置pojo类别名 return sqlSessionFactoryBean; } @Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer(); mapperScannerConfigurer.setBasePackage("com.hhh.dao");//扫描dao层,并帮dao层的接口类创建代理对象bean return mapperScannerConfigurer; } }
SpringMvcConfig配置类
@Configuration @ComponentScan("com.hhh.controller") @EnableWebMvc//开启辅助功能 public class SpringMvcConfig { }
ServletContainerInitConfig配置类
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { //加载spring核心配置类 @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } //加载springMVC核心配置类 @Override protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } //设置哪些请求路径交给springMVC管理 @Override protected String[] getServletMappings() { return new String[]{"/"}; } //设置post中文请求乱码 @Override protected 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; @Override public 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; @Override public 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 { @Autowired private BookDao bookDao; @Override public Boolean save(Book book) { return bookDao.save(book)>0;//大于0为真 } @Override public List<Book> getAll() { return bookDao.getAll(); } @Override public Book getById(Integer id) { return bookDao.getById(id); } @Override public Boolean deleteById(Integer id) { return bookDao.deleteById(id)>0; } @Override public Boolean updateById(UpdateBook updateBook) { return bookDao.updateById(updateBook)>0; } }
测试一下
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class)//加载spring核心配置类 public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetAll(){ List<Book> list = bookService.getAll(); System.out.println(list); } @Test public void testGetById(){ Book book= bookService.getById(2); System.out.println(book); } @Test public void testSave(){ Book book = new Book(); book.setName("hh"); book.setDescription("aa"); book.setScore(90); Boolean aBoolean = bookService.save(book); System.out.println(aBoolean);//true System.out.println("id="+book.getId());//11 } @Test public 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); } @Test public 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 { @Autowired private BookService bookService; @PostMapping public String save(@RequestBody Book book){//解析json对象 Boolean b = bookService.save(book); return b?"保存成功":"保存失败"; //return "保存成功"; } @GetMapping public List<Book>getAll(){ return bookService.getAll(); } @GetMapping("/{id}") public Book getById(@PathVariable Integer id){//从路径中获取值 return bookService.getById(id); } @PutMapping public 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;//响应信息,可有可无
@Override
public 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 {
@Autowired
private BookService bookService;
@PostMapping
public 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);
}
@GetMapping
public 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);
}
@PutMapping
public 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 {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");//执行原方法之前
return true;//返回true才能放行去访问controller
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandler");
}
@Override
public 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 {
@Autowired
private MyInterceptor myInterceptor;
@Override
public 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 {
@Autowired
private MyInterceptor myInterceptor;
@Autowired
private MyInterceptor2 myInterceptor2;
@Autowired
private MyInterceptor3 myInterceptor3;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/books","/books/*");//设置拦截的路径
registry.addInterceptor(myInterceptor2).addPathPatterns("/books","/books/*");
registry.addInterceptor(myInterceptor3).addPathPatterns("/books","/books/*");
}
}
执行的顺序就是加载的顺序
结果: