2020-12-19

springMVC第三天学习笔记


SSM 整合

1.数据库环境搭建

数据库表结构如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3qxnsHE-1608379310525)(.\img\表结构.jpg)]

建表sql语句见 资料\ssm.sql

2.工程环境搭建

2.1 在project中创建web模块

2.2 在pom.xml文件中导入坐标

<packaging>war</packaging>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <!--mybatis环境-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.3</version>
    </dependency>
    <!--mysql环境-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <!--spring整合jdbc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--spring整合mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!--druid连接池-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    <!--分页插件坐标-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.2</version>
    </dependency>
    <!--springmvc环境-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
    <!--jackson相关坐标3个-->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.0</version>
    </dependency>
    <!--servlet环境-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    
    <!--其他组件-->
    <!--junit单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!--spring整合junit-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>

<build>
    <!--设置插件-->
    <plugins>
        <!--具体的插件配置-->
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <configuration>
                <port>80</port>
                <path>/</path>
            </configuration>
        </plugin>
    </plugins>
</build>

2.3 补全工程目录,创建基本包结构
在这里插入图片描述
2.4 在domain包下创建实体类

  • User.java

    public class User {
        private Integer uid;
        private String username;
        private String password;
        private String realname;
        private Integer gender;
        private Date birthday;
        // get set 省略
    }
    
  • Result.java

    public class Result {
        // 是否成功
        private boolean flag;
        // 成功之后响应的核心数据
        private Object data;
        // 提示消息
        private String message;
        // 状态码
        private Integer code;
        // 成功
        public Result(Object data, String message, Integer code) {
            this.flag = true;
            this.data = data;
            this.message = message;
            this.code = code;
        }
    
        // 失败
        public Result(String message, Integer code) {
            this.flag = false;
            this.message = message;
            this.code = code;
        }
        // get  set 省略
    }
    
  • Code.java

    public class Code {
        //    操作结果编码
        public static final Integer SAVE_OK = 20011;
        public static final Integer UPDATE_OK = 20021;
        public static final Integer DELETE_OK = 20031;
        public static final Integer GET_OK = 20041;
    
        public static final Integer SAVE_ERROR = 20010;
        public static final Integer UPDATE_ERROR = 20020;
        public static final Integer DELETE_ERROR = 20030;
        public static final Integer GET_ERROR = 20040;
        //    校验结果编码
        public static final Integer DATA_LENGTH_ERROR = 30001;
        public static final Integer DATA_VALUE_ERROR = 30002;
    }
    

3.springmvc基础环境完善

3.1 配置web.xml文件

<!--请求乱码过滤器-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!--前端控制器-->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3.2 在resources目录下创建spring-mvc.xml文件,编写基本配置

<!--包扫描:暂时扫描itheima包-->
<context:component-scan base-package="com.itheima"/>

<!--注解驱动-->
<mnc:annotation-driven/>

<!--静态资源排除-->
<mvc:default-servlet-handler/>

3.3 在controller包下创建UserController,在类中创建测试方法

@Controller
public class UserController {
    @RequestMapping("/helloWorld")
    @ResponseBody
    public String helloWorld(){
        return "helloWorld";
    }
}

3.4 在浏览器中输入http://localhost/helloWorld 进行测试

在这里插入图片描述

4.整合mybatis

4.1 在resources下创建jdbc.properties配置文件

jdbc.driver=com.mysql.jdbc.Driver
# 自行修改ip地址
jdbc.url=jdbc:mysql://192.168.93.129:3306/ssm
jdbc.username=root
jdbc.password=root

4.2 在dao包下创建UserDao接口

public interface UserDao {
    public List<User> findAll();
}

4.3 在resources下的com/itheima/dao目录下创建UserDao接口对应的映射配置文件UserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.UserDao">
    <select id="findAll" resultType="User">
        select * from user
    </select>
</mapper>

4.4 在service包下创建UserService接口

public interface UserService {
    public List<User> findAll();
}

4.5 在service.impl包下创建UserServiceImpl实现类

@Service("userService")
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public List<User> findAll() {
        return userDao.findAll();
    }
}

4.6 在springmvc配置文件中添加整合mybatis相关配置

<!--加载jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

<!--配置创建SqlSession对象的工厂Bean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.itheima.domain"/>
</bean>

<!--配置dao接口所在包-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.itheima.dao"/>
</bean>

4.7 修改UserController,注入UserService,调用UserService的findAll方法

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    
    @RequestMapping("/findAll")
    @ResponseBody
    public Result findAll(){
        List<User> userList = userService.findAll();
        Result result = new Result(userList,"查询成功", Code.GET_OK);
        return result;
    }
}

4.8 通过postman进行测试

在这里插入图片描述

整合后工程结构
在这里插入图片描述

5.spring与springmvc配置分离

实际开发中,为了便于维护,spring-mvc.xml文件中只负责springmvc针对web层的相关配置,对于其它层的信息应该配置到spring的applicationContext.xml文件中。因此,需要将spring-mvc.xml文件中部分内容进行分离。

5.1 在resources下创建spring的配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--包扫描:不扫描Controller注解-->
    <context:component-scan base-package="com.itheima">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--加载jdbc.properties-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置创建SqlSession对象的工厂Bean-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.itheima.domain"/>
    </bean>

    <!--配置dao接口所在包-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.itheima.dao"/>
    </bean>
</beans>

此配置文件中配置springmvc之外的内容,如service,dao,aop,事务相关配置。

存在的问题

目前存在的问题是,spring-mvc.xml文件已经通过DispatcherServlet加载,而applicationContext.xml文件没有被加载。

解决方案

  • spring-web 包中提供了一个继承自ServletContextListener的监听器ContextLoaderListener
  • 该监听器用于在服务器启动时加载spring的核心配置文件
  • 由于spring的核心配置文件名是可以自定义的,所以需要通过全局初始化参数指定配置文件的名称

5.2 修改web.xml文件,配置监听器,用于加载spring核心配置文件,并通过全局初始化参数指定配置文件名称

<!--配置用于加载spring核心配置文件的监听器-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置全局初始化参数,指定spring核心配置文件名称-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

5.3 修改spring-mvc.xml文件中的包扫描,只扫描controller

<!--包扫描-->
<context:component-scan base-package="com.itheima.controller"/>

5.4 重启项目,进行测试

6.事务管理配置

6.0 导入aspectjweaver坐标

<!--aspectjweaver-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

6.1 修改applicationContext.xml文件,加入事务管理器配置,并开启注解事务支持

<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--开启注解事务支持-->
<tx:annotation-driven/>

6.2 在需要进行事务管理的业务接口中加入@Transactional注解

  • 接口上指定通用配置
  • 方法上指定特有配置
@Transactional
public interface UserService {
    @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
    public List<User> findAll();
}

7. 分页插件配置

7.1 修改applicationContext.xml,在SqlSessionFactoryBean配置中加入分页插件配置

<!--配置创建SqlSession对象的工厂Bean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.itheima.domain"/>
    <!--配置分页插件-->
    <property name="plugins">
        <array>
            <bean class="com.github.pagehelper.PageInterceptor">
                <!--可选配置-->
                <property name="properties">
                    <props>
                        <!--配置方言-->
                        <prop key="helperDialect">mysql</prop>
                        <!--查询页码大于最大页码时返回最后一页数据-->
                        <prop key="reasonable">true</prop>
                    </props>
                </property>
            </bean>
        </array>
    </property>
</bean>

7.2 修改业务层代码,加入分页参数

  • UserService.java

    @Transactional
    public interface UserService {
        @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
        public PageInfo findAll(int pageNum, int pageSize);
    }
    
  • UserServiceImpl.java

    @Service("userService")
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserDao userDao;
        @Override
        public PageInfo findAll(int pageNum, int pageSize) {
            // 设置分页参数
            PageHelper.startPage(pageNum, pageSize);
            List<User> list = userDao.findAll();
            return new PageInfo(list);
        }
    }
    

7.3 修改controller代码,加入分页参数

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/findAll")
    @ResponseBody
    public Result findAll(int pageNum, int pageSize){
        PageInfo pageInfo = userService.findAll(pageNum, pageSize);
        Result result = new Result(pageInfo,"查询成功", Code.GET_OK);
        return result;
    }
}

7.4 重启项目,通过Postman进行测试

在这里插入图片描述

返回数据如下:

{
    "flag": true,
    "data": {
        "pageNum": 1,
        "pageSize": 3,
        "size": 3,
        "startRow": 1,
        "endRow": 3,
        "total": 8,
        "pages": 3,
        "list": [
            {
                "uid": 1,
                "username": "zhangsan",
                "password": "123",
                "realname": "张三",
                "gender": 0,
                "birthday": 652806000000
            },
            {
                "uid": 2,
                "username": "lisi",
                "password": "123",
                "realname": "李四",
                "gender": 0,
                "birthday": 650041200000
            },
            {
                "uid": 3,
                "username": "wangwu",
                "password": "123",
                "realname": "王五",
                "gender": 1,
                "birthday": 647276400000
            }
        ],
        "prePage": 0,
        "nextPage": 2,
        "isFirstPage": true,
        "isLastPage": false,
        "hasPreviousPage": false,
        "hasNextPage": true,
        "navigatePages": 8,
        "navigatepageNums": [
            1,
            2,
            3
        ],
        "navigateFirstPage": 1,
        "navigateLastPage": 3,
        "firstPage": 1,
        "lastPage": 3
    },
    "message": "查询成功",
    "code": 20041
}

8.统一异常处理配置

8.1 自定义异常类com.itheima.exception.BusinessException

public class BusinessException extends RuntimeException {
    // 用于封装错误的状态码
    private Integer code;
    
    public BusinessException(Integer code) {
        this.code = code;
    }

    public BusinessException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    public BusinessException(String message, Throwable cause, Integer code) {
        super(message, cause);
        this.code = code;
    }
	// 必须生成get方法,用于在异常处理器中获取异常错误码
    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }
}

8.2 创建基于注解的统一异常处理器com.itheima.exception.ProjectExceptionAdvice

@Component
@ControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result doBusinessException(BusinessException e){
        // 获取异常的状态码
        Integer code = e.getCode();
        // 获取异常的提示消息
        String message = e.getMessage();
        // 将状态码和提示消息封装到Result对象
        Result result = new Result(message, code);
        return result;
    }
}

8.3 修改UserController中的findAll方法,加入页码校验逻辑,页码不合法时抛出自定义异常

@RequestMapping("/findAll")
@ResponseBody
public Result findAll(int pageNum, int pageSize){
    if (pageNum <= 0){
        throw new BusinessException("页码必须大于0", Code.DATA_VALUE_ERROR);
    }
    PageInfo pageInfo = userService.findAll(pageNum, pageSize);
    Result result = new Result(pageInfo,"查询成功", Code.GET_OK);
    return result;
}

8.4 重启服务器,通过Postman进行测试,测试时pageNum参数设置为小于1的值

在这里插入图片描述

9.配置类替换web,applicationContext,spring-mvc三个xml配置文件

9.1 替换applicationContext类

SpringConfig.java

@Configuration
@ComponentScan(value = "com.itheima",
    excludeFilters = @ComponentScan.Filter(
            type = FilterType.ANNOTATION,
            classes = Controller.class
    )
)
@EnableTransactionManagement
@Import(JdbcConfig.class)
public class SpringConfig {
    @Bean("transactionManager")
    public PlatformTransactionManager getPlatformTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}

JdbcConfig.java

@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String usernmae;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setPassword(password);
        dataSource.setUsername(usernmae);
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        return dataSource;
    }
}

MybatisConfig.java

@Configuration
@Import(JdbcConfig.class)
public class MybatisConfig {

    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.itheima.dao");
        return configurer;
    }

    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource,
                                                          Interceptor interceptor){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setTypeAliasesPackage("com.itheima.domain");
        factoryBean.setDataSource(dataSource);
        factoryBean.setPlugins(interceptor);
        return factoryBean;
    }

    @Bean
    public Interceptor getInterceptor(){
        PageInterceptor pageInterceptor = new PageInterceptor();
        Properties properties = new Properties();
        properties.setProperty("helperDialect","mysql");
        properties.setProperty("reasonable","true");
        pageInterceptor.setProperties(properties);
        return pageInterceptor;
    }
}

9.2 替换spring-mvc类

@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

9…3 替换web类

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext app = new AnnotationConfigWebApplicationContext();
        app.register(SpringMvcConfig.class);
        return app;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext app = new AnnotationConfigWebApplicationContext();
        app.register(SpringConfig.class);
        return app;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter",filter);
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD),false,"/*");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值