SSM整合

SSM整合

1.项目结构分析

如图所示,SSM框架大致如上,主要由配置类、业务层、表现层、数据层组成。下面会对每个包中的代码进行分析和解释。

  • 配置类(config):加载初始化Bean,加载配置文件,初始化Spring核心容器和Tomcat中Servlet容器,数据库相关的配置。
  • 业务层(Service):实现业务逻辑。
  • 数据层(dao):负责数据库操作,实现增删改查等数据库操作。
  • 表现层(controller):调用业务层提供各种方法实现一些组合操作,满足用户需求,并返回网页页面需要的数据。

需要导入的依赖坐标

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.2.22.RELEASE</version>
        <scope>test</scope>
    </dependency>
    <!--提供spring所有基础功能-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.22.RELEASE</version>
    </dependency>
    <!--tomcat中servlet容器需要-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <!--提供数据格式转换-->
    <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.11</version>
    </dependency>
    <!-- spring中管理mybatis需要-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.1.0</version>
    </dependency>
    <!--连接mysql数据库-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.29</version>
    </dependency>
    <!--数据连接池-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.15</version>
    </dependency>
    <!--提供jdbc基本功能 主要是使用了它的事务管理 其他基础功能在spring-webmvc已有-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.22.RELEASE</version>
    </dependency>
    <!--实现实体类的各种便捷操作 不是刚需-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
        <scope>provided</scope>
    </dependency>
    <!--提供测试功能-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2. config包解析

2.1. 目录结构

主要五个配置类,起作用分别为:

  • JbbcConfig:配置DataSource(数据库)和事务管理。
  • MyBatisConfig:配置MyBatis的扫描domain类和dao,实现SQL语句。
  • ServletContainerConfig:将Spring核心容器的Bean加载到Servlet容器中,能够在web容器启动项目的SpringMvc,和对访问资源路径的判断处理。
  • SpringConfig:管理Spring容器的Bean的加载和初始化。
  • SpringMvcConfig:在web容器中启动该项目。

2.2. SpringMvcConfig实现

@Configuration
@ComponentScan({"com.cqut.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer{
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/html/**").addResourceLocations("/html/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
    }
}
  • @Configuration:声明为配置类,加载各种资源。
  • @ComponentScan:扫描包,springmvc主要是控制表现层,需要对表现层的包"com.cqut.controller"进行扫描,必要时为了加载某些配置类也可以对配置类所在的包"com.cqut.config"进行扫描。
  • @EnableWebMvc:开启数据格式转换的功能,还有其他等功能。
  • 这里的SpringMvcConfig继承了WebMvcConfigurer类,可以覆盖父类提供的方法,对静态资源进行放行,和设置拦截器。
    • public void addResourceHandlers(ResourceHandlerRegistry registry):对静态资源进行放行,例如:当url中发起请求html/*的路径访问,则访问对应目录下的文件,而不是url的servlte请求。
    • public void addInterceptors(InterceptorRegistry registry):对servlet请求设置拦截器,当访问/books/books/*进行拦截处理。这里的拦截器是通过自动注@Autowired入拿到的。
  • 这种写法的侵入式较强,将Spring和SpringMvc绑定在了一起。可以有以下写法,将对静态资源的访问和拦截器在写一个配置类。
@Configuration
public class SpringMvcSupportConfig extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/html/**").addResourceLocations("/html/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*");
    }
}
@Configuration
@ComponentScan({"com.cqut.controller","com.cqut.config"})
@EnableWebMvc
public class SpringMvcConfig{
}

拦截器

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行
  • 作用:
    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行
  • 拦截器的主要思想:AOP面向切面编程
  • Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • Filter对所有访问进行增强,Interceptor仅对SpringMVC的访问增强
  • 拦截器流程如下

这里需要对拦截器的执行流程理解,在此基础上对拦截器链进行充分理解,这里不在赘述。

2.3. SpringConfig实现

@Configuration
@ComponentScan({"com.cqut.service"})
@Import({JdbcConfig.class, MyBatisConfig.class})
@PropertySource({"classpath:jdbc.properties"})
public class SpringConfig {
}
  • 这里对"com.cqut.service"业务层进行扫描,不需要再对"com.cqut.dao"数据库包进行扫描了,具体实现由mybatis来实现。
  • @Import({JdbcConfig.class, MyBatisConfig.class})这里到导入了JdbcConfigMyBatisConfig两个配置类进行导入,得到了数据库连接池,对数据库进行操作。
  • @PropertySource({"classpath:jdbc.properties"}):这个注意要写上classpath,不然可能找不到文件在哪报错。文件位置见目录结构。

2.4. 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;
    }
    @Bean
    public PlatformTransactionManager transactionManager (DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
  • @Value("${xxx}"):通过读取jdbc.properties文件来赋值。
  • public DataSource dataSource():建立数据库连接池。这里使用的是druid中提供的数据库操作。
  • public PlatformTransactionManager transactionManager (DataSource dataSource):事务管理,保证事务的一致性。
  • 方法前加上@Bean会把方法的返回值初始化为一个Bean,同时public PlatformTransactionManager transactionManager (DataSource dataSource)的形参dataSourcepublic DataSource dataSource()初始化的Bean要是同一个对象。

2.5. MybatisConfig实现

public class MyBatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setTypeAliasesPackage("com.cqut.domain");
        return factoryBean;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("com.cqut.dao");
        return mapperScannerConfigurer;
    }
}
  • public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource):对实体类进行映射
  • public MapperScannerConfigurer mapperScannerConfigurer():对数据层(dao)进行映射

2.6. ServletContainerInitConfig实现

public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("utf-8");
        return new Filter[]{filter};
    }
}
  • 注意父类AbstractAnnotationConfigDispatcherServletInitializer
  • protected Class<?>[] getRootConfigClasses():是对SpringConfig的设置。
  • protected Class<?>[] getServletConfigClasses():是对SpringMvcConfig的设置。
  • protected String[] getServletMappings():设置请求路径来对请求处理。
  • protected Filter[] getServletFilters()可以设置多个过滤器,这里只对body中中文乱码设置过滤器进行处理。

3. controller包解析

3.1.目录结构

  • 表现层:包括了表现层、数据格式统一,异常处理等处理类。

3.2. ProjectInterceptor实现

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle ....");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle ....");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion ....");
    }
}
  • 自定一个拦截器,可以再执行流程中对数据进行处理。
  • 添加上@Component,在SpringMvcConfig扫描包可以扫描到初始定义为bean。
  • public boolean preHandle()的返回值决定是否是执行controller中的代码,如果为true执行,false中止方法执行。

3.3. Code实现

public class Code {
    public static Integer ADD_OK = 20011;
    public static Integer DELETE_OK = 20021;
    public static Integer SELECT_OK = 20031;
    public static Integer UP_DATA_OK = 20041;

    public static Integer ADD_ERR = 20010;
    public static Integer DELETE_ERR = 20020;
    public static Integer SELECT_ERR = 20030;
    public static Integer UP_DATA_ERR = 20040;

    public static Integer SYSTEM_ERR = 50010;
    public static Integer SYSTEM_TIMEOUT_ERR = 50020;
    public static Integer BUSINESS_ERR = 50030;
    public static Integer SYSTEM_UNKNOW_ERR = 59999;
}
  • 定义了各种状态码,便于前端的数据使用。

3.4. ProjectExceptionAdvice实现

@RestControllerAdvice
public class ProjectExceptionAdvice{
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException exception){
        return new Result(Code.SYSTEM_ERR, null, exception.getMessage());
    }
    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException exception){
        return new Result(Code.BUSINESS_ERR, null, exception.getMessage());
    }
    @ExceptionHandler(Exception.class)
    public Result doException(Exception exception){
        return new Result(Code.SYSTEM_TIMEOUT_ERR, null, "系统超时,请稍后再试");
    }
}
  • 针对各种异常进行处理,也便于前端来处理异常情况。
  • @RestControllerAdvice是一个用于全局异常处理的注解。它可以用于定义一个类,该类中的方法会在控制器中抛出异常时被调用,从而统一处理异常。可以将全局异常处理逻辑集中到一个类中,减少代码重复,提高代码的可维护性和可读性。
  • @ExceptionHandler 是一个注解,用于标记一个方法,该方法用于处理特定类型的异常。当控制器中抛出指定类型的异常时,被 @ExceptionHandler 注解标记的方法会被调用,用于处理该异常。该方法可以包含任意的业务逻辑,比如记录日志、返回自定义的错误信息等。
  • SystemExceptionBusinessException是自定义的异常类。

3.5. Result实现

@Data
public class Result {
    private Integer code;
    private Object data;
    private String 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;
    }
}
  • 后端返回给前端的数据做一个统一的数据格式封装,同一个格式,包括状态码、数据、异常信息。

3.6. BookController实现

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;

    @PostMapping
    public Result add(@RequestBody Book book) {
        int i = bookService.add(book);
        return new Result(i > 0 ? Code.ADD_OK: Code.ADD_ERR, i > 0 ? "True" : "False");
    }

    @DeleteMapping("/{id}")
    public Result deleteById(@PathVariable int id) {
        int i = bookService.deleteById(id);
        return new Result(i > 0 ? Code.DELETE_OK: Code.DELETE_ERR, i > 0 ? "True" : "False");
    }

    @PutMapping()
    public Result upDataById(@RequestBody Book book) {
        int i = bookService.upDataById(book);
        return new Result(i > 0 ? Code.UP_DATA_OK: Code.UP_DATA_ERR, i > 0 ? "True" : "False");
    }

    @GetMapping("/{id}")
    public Result selectById(@PathVariable int id) {
        Book book = bookService.selectById(id);
        return new Result(book != null? Code.SELECT_OK: Code.SELECT_ERR, book);
    }

    @GetMapping
    public Result selectAll() {
        List<Book> books = bookService.selectAll();
        return new Result(books != null? Code.SELECT_OK: Code.SELECT_ERR, books);
    }
}
  • @RestController

    @RestController 是一个注解,用于标记一个类或方法,表示该类或方法是一个控制器(Controller),并且返回的结果直接写入 HTTP 响应体中。

    @RestController 注解的作用包括:

    1. 标记类为控制器:当一个类被@RestController注解标记时,Spring 将会扫描该类,并将其注册为一个控制器,用于处理客户端的 HTTP 请求。
    2. 处理请求和返回响应:被 @RestController 注解标记的方法可以通过 @RequestMapping 注解来处理特定的 HTTP 请求,包括 GET、POST、PUT、DELETE 等。方法的返回值会被自动转换为 JSON 或 XML 格式,并写入 HTTP 响应体中,返回给客户端。
    3. 自动序列化和反序列化:被 @RestController 注解标记的方法可以直接接收和返回 Java 对象,Spring 会自动进行序列化和反序列化,将对象转换为 JSON 或 XML 格式,或者将请求体中的 JSON 或 XML 数据转换为 Java 对象
  • 统一使用规定好的Result数据格式进行数据返回。

4. dao包解析

public interface BookDao {
    @Insert("insert into tb_books (name, series, description) values(#{name}, #{series}, #{description})")
    public int add(Book book);

    @Delete("delete from tb_books where id = #{id}")
    public int deleteById(int id);

    @Update("update tb_books set name = #{name}, series = #{series}, description = #{description} where id = #{id}")
    public int upDataById(Book book);

    @Select("select * from tb_books where id = #{id};")
    public Book selectById(int id);

    @Select("select * from tb_books")
    public List<Book> selectAll();

}
  • SQL语句执行,这里通过注解方式实现的,若查询条件复杂还是使用xml形式来书写SQL语句。
  • 这里需要注意数据库的字段名称、参数名称对应的问题。

5. domain包

@Data
public class Book {
    private Integer id;
    private String name;
    private String series;
    private String description;
}

6. exception包

  • 自定义了两个类SystemException(系统异常)和BusinessException(业务异常)
public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return 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 class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return 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;
    }
}

7. service包

7.1. 目录结构

  • 定义一个service的接口,通过结构来定义一个具体的实现类。

7.2. 代码实现

public interface BookService {

    public int add(Book book);

    public int deleteById(int id);

    public int upDataById(Book book);

    public Book selectById(int id);

    public List<Book> selectAll();
}
@Service
@Transactional
public class BookServiceImp implements BookService {

    @Autowired
    private BookDao bookDao;

    public int add(Book book) {
        return bookDao.add(book);
    }

    public int deleteById(int id) {
        return bookDao.deleteById(id);
    }

    public int upDataById(Book book) {
        return bookDao.upDataById(book);
    }

    public Book selectById(int id) {
        return bookDao.selectById(id);
    }

    public List<Book> selectAll() {
        return bookDao.selectAll();
    }
}
  • @Service 注解的作用是将一个类标记为服务组件,用于实现业务逻辑的处理,并作为控制器和持久层之间的中间层,提供可重用、可测试和可维护的代码。

  • @Transactional 是一个注解,用于标记一个方法或类,表示该方法或类需要在事务管理下进行操作。

    @Transactional 注解的作用包括:

    1. 启用事务管理:当一个方法或类被 @Transactional 注解标记时,Spring 将会为该方法或类启用事务管理,确保方法的执行在一个事务中进行。

    2. 提供事务边界:被 @Transactional 注解标记的方法或类将会创建一个事务边界,该边界内的数据库操作将被视为一个原子操作,要么全部成功提交,要么全部失败回滚。

    3. 控制事务传播行为:通过 @Transactional 注解的属性,可以控制事务的传播行为,包括传播行为、隔离级别、只读属性等。例如,可以指定一个方法在一个已存在的事务中运行,或者在没有事务的情况下启动一个新的事务。

    4. 简化事务管理:使用 @Transactional 注解可以简化事务管理的配置,不再需要手动编写事务的开始、提交、回滚等代码,Spring 会自动处理事务的管理。

  • @Service 注解的作用是将一个类标记为服务组件,用于实现业务逻辑的处理,并作为控制器和持久层之间的中间层,提供可重用、可测试和可维护的代码。

  • @Transactional 是一个注解,用于标记一个方法或类,表示该方法或类需要在事务管理下进行操作。

    @Transactional 注解的作用包括:

    1. 启用事务管理:当一个方法或类被 @Transactional 注解标记时,Spring 将会为该方法或类启用事务管理,确保方法的执行在一个事务中进行。

    2. 提供事务边界:被 @Transactional 注解标记的方法或类将会创建一个事务边界,该边界内的数据库操作将被视为一个原子操作,要么全部成功提交,要么全部失败回滚。

    3. 控制事务传播行为:通过 @Transactional 注解的属性,可以控制事务的传播行为,包括传播行为、隔离级别、只读属性等。例如,可以指定一个方法在一个已存在的事务中运行,或者在没有事务的情况下启动一个新的事务。

    4. 简化事务管理:使用 @Transactional 注解可以简化事务管理的配置,不再需要手动编写事务的开始、提交、回滚等代码,Spring 会自动处理事务的管理。

    总之,@Transactional 注解的作用是启用事务管理,并为方法或类提供事务边界,控制事务的传播行为,简化事务管理的配置。使用 @Transactional 注解可以确保方法的执行在一个事务中进行,保证数据的一致性和完整性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值