03-环境搭建

1 环境搭建总体目标

03-环境搭建_第1张图片

2 创建工程

2.1 项目架构图

03-环境搭建_第2张图片

2.2 工程创建计划

atcrowdfunding01-admin-parent

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding01-admin-parent
  • packaging:pom

atcrowdfunding02-admin-webui

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding02-admin-webui
  • packaging:war

atcrowdfunding03-admin-component

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding03-admin-component
  • packaging:jar

atcrowdfunding04-admin-entity

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding04-admin-entity
  • packaging:jar

atcrowdfunding05-common-util

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding05-common-util
  • packaging:jar

atcrowdfunding06-common-reverse

  • groupId:com.atguigu.crowd
  • artifactId:atcrowdfunding06-common-reverse
  • packaging:jar

2.3 Maven 工程和 Maven 模块

  创建工程时参与继承、聚合的工程以“Maven module”的方式创建,继承和聚合 可以自动配置出来。具体做法是创建 parent 工程后,在 parent 工程上点右键,new→ Maven module
03-环境搭建_第3张图片
同时继承和聚合得到了自动化配置。

2.4 建立工程之间的依赖关系

webui 依赖 component
component 依赖 entity
component 依赖 util

3 创建数据库和数据库表

3.1 物理建模

3.1.1 理论

  • 第一范式:数据库表中的每一列都不可再分,也就是原子性
    03-环境搭建_第4张图片
    这个表中“部门”和“岗位”应该拆分成两个字段:“部门名称”、“岗位”。
    03-环境搭建_第5张图片
    这样才能够专门针对“部门”或“岗位”进行查询。
  • 第二范式:在满足第一范式基础上要求每个字段都和主键完整相关,而不是仅和主键部分相关(主要针对联合主键而言)
    03-环境搭建_第6张图片
      “订单详情表”使用“订单编号”和“产品编号”作为联合主键。此时“产 品价格”、 “产品数量”都和联合主键整体相关,但“订单金额”和“下单时间” 只和联合主键中的“订单编号”相关,和“产品编号”无关。所以只关联了主 键中的部分字段,不满足第二范式。
      “把“订单金额”和“下单时间”移到订单表就符合第二范式了03-环境搭建_第7张图片
  • 第三范式:表中的非主键字段和主键字段直接相关,不允许间接相关
    03-环境搭建_第8张图片
      上面表中的“部门名称”和“员工编号”的关系是“员工编号”→“部门编号” →“部门名称”,不是直接相关。此时会带来下列问题:
  • 数据冗余:“部门名称”多次重复出现。
  • 插入异常:组建一个新部门时没有员工信息,也就无法单独插入部门 信息。就算强行插入部门信息,员工表中没有员工信息的记录同样是 非法记录。
  • 删除异常:删除员工信息会连带删除部门信息导致部门信息意外丢失。
  • 更新异常:哪怕只修改一个部门的名称也要更新多条员工记录。 正确的做法是:把上表拆分成两张表,以外键形式关联
    在这里插入图片描述
      “部门编号”和“员工编号”是直接相关的。
      第二范式的另一种表述方式是:两张表要通过外键关联,不保存冗余字段。例 如:不能在“员工表”中存储“部门名称”。
    3.1.2 实践
  • 规则的变通
      三大范式是设计数据库表结构的规则约束,但是在实际开发中允许局部变通
      比如为了快速查询到关联数据可能会允许冗余字段的存在。例如在员工表 中存储部门名称虽然违背第三范式,但是免去了对部门表的关联查询。
  • 根据业务功能设计数据库表
    • 看得见的字段
        能够从需求文档或原型页面上直接看到的数据都需要设计对应的数 据库表、字段来存储。03-环境搭建_第9张图片
      根据上面的原型页面我们看到管理员表需要包含如下字段:
      • 账号
      • 密码
      • 名称
      • 邮箱地址
    • 看不见的字段
        除了能够直接从需求文档中看到的字段,实际开发中往往还会包含一 些其他字段来保存其他相关数据。
        例如:管理员表需要再增加如下字段以有利于数据维护
      • 主键
      • 创建时间
    • 冗余字段
         为了避免建表时考虑不周有所遗漏,到后期再修改表结构非常麻烦, 所以也有的团队会设置一些额外的冗余字段备用
    • 实际开发对接
         实际开发中除了一些各个模块都需要使用的公共表在项目启动时创 建好,其他专属于各个模块的表由该模块的负责人创建。但通常开发人员 不能直接操作数据库服务器,所以需要把建表的 SQL 语句发送给运维工程 师执行创建操作。

3.2 创建数据库

CREATE DATABASE project_crowd CHARACTER SET utf8;

3.3 创建管理员数据库表

CREATE TABLE `t_admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `login_acct` varchar(255) NOT NULL COMMENT '登录账号',
  `user_pswd` char(32) NOT NULL COMMENT '登录密码 ',
  `user_name` varchar(255) NOT NULL COMMENT '昵称 ',
  `email` varchar(255) NOT NULL COMMENT '邮件地址 ',
  `create_time` char(19) COMMENT '创建时间 ',
  PRIMARY KEY (`id`)
);

4 基于 Maven 的 MyBatis 逆向工程

4.1 atcrowdfunding06-common-reverse工程的pom 配置

<!-- 依赖 MyBatis 核心包 -->
<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.8</version>
    </dependency>
</dependencies>
<!-- 控制 Maven 在构建过程中相关配置 -->
<build>
    <!-- 构建过程中用到的插件 -->
    <plugins>
        <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>
            <!-- 插件的依赖 -->
            <dependencies>
                <!-- 逆向工程的核心依赖 -->
                <dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
                </dependency>
                <!-- 数据库连接池 -->
                <dependency>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                    <version>0.9.2</version>
                </dependency>
                <!--MySQL 驱动 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.8</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

4.2 在atcrowdfunding06-common-reverse的resources目录下的generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- mybatis-generator:generate -->
    <context id="atguiguTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:;false:-->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection
                driverClass="com.mysql.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/project_crowd?characterEncoding=utf8"
                userId="root"
                password="root">
        </jdbcConnection>
        <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL
            和 NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
        <!-- targetProject:生成Entity类的路径 -->
        <javaModelGenerator targetProject=".\src\main\java"
                            targetPackage="com.atguigu.crowd.entity">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:XxxMapper.xml映射文件生成的路径 -->
        <sqlMapGenerator targetProject=".\src\main\java"
                         targetPackage="com.atguigu.crowd.mapper">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:Mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetProject=".\src\main\java"
                             targetPackage="com.atguigu.crowd.mapper">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 数据库表名字和我们的entity类对应的映射指定 -->
        <table tableName="t_admin" domainObjectName="Admin" />
    </context>
</generatorConfiguration> 

4.3 在atcrowdfunding06-common-reverse点击界面右边的Maven—>Plugins—>mybatis-generator下的mybatis-generator:generate命令,代码生成,并在Admin.java文件添加无参构造、有参构造、tostring方法

4.4 逆向工程生成的资源各归各位
   WebUI 工程将来在 Tomcat 上运行时,现在 resources 目录下的资源会直接放在 WEB-INF/classes 目录(也就是类路径)下,所以放在 resources 目录下运行的时候更容 易找到
03-环境搭建_第10张图片
03-环境搭建_第11张图片
03-环境搭建_第12张图片
并在atcrowdfunding03-admin-component的pom下添加依赖包

<!-- 依赖 MyBatis 核心包 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.8</version>
    </dependency>

5 父工程atcrowdfunding01-admin-parent依赖管理

5.1 版本声明

<properties> <!-- 声明属性,对 Spring 的版本进行统一管理 -->
    <atguigu.spring.version>4.3.20.RELEASE</atguigu.spring.version>
    <!-- 声明属性,对 SpringSecurity 的版本进行统一管理 -->
    <atguigu.spring.security.version>4.2.10.RELEASE</atguigu.spring.security.version>
</properties>

5.2 依赖管理

<dependencyManagement>
    <dependencies> <!--Spring 依赖 --> <!--https://mvnrepository.com/artifact/org.springframework/spring-orm-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${atguigu.spring.version}</version>
        </dependency> <!--https://mvnrepository.com/artifact/org.springframework/spring-webmvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${atguigu.spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${atguigu.spring.version}</version>
        </dependency> <!--https://mvnrepository.com/artifact/org.aspectj/aspectjweaver-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency> <!--https://mvnrepository.com/artifact/cglib/cglib-->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>
        <!-- 数据库依赖 --> <!--MySQL 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.3</version>
        </dependency>
        <!-- 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
        <!--MyBatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <!--MyBatis 与 Spring 整合 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>
        <!--MyBatis 分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.0.0</version>
        </dependency><!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- 其他日志框架的中间转换包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jul-to-slf4j</artifactId>
            <version>1.7.25</version>
        </dependency>
        <!--Spring 进行 JSON 数据转换依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.8</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
        <!--JSTL 标签库 -->
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency><!--junit 测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- 引入 Servlet 容器中相关依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <!--JSP 页面使用的依赖 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1.3-b06</version>
            <scope>provided</scope>
        </dependency>
        <!--https://mvnrepository.com/artifact/com.google.code.gson/gson-->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>
        <!--SpringSecurity 对 Web 应用进行权限管理 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.2.10.RELEASE</version>
        </dependency>
        <!--SpringSecurity 配置 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.2.10.RELEASE</version>
        </dependency>
        <!--SpringSecurity 标签库 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>4.2.10.RELEASE</version>
        </dependency>
    </dependencies>
</dependencyManagement>

5.3 依赖信息来源

  • 到专门网站搜索
    https://mvnrepository.com
  • 调试
    根据实际运行情况,确认 jar 包之间是否兼容
    SpringMVC 需要 jackson 的支持,来处理 JSON 数据。但是 SpringMVC 并没有依 赖 jackson。所以需要我们自己保证 jar 包之间的兼容性。

6 Spring 整合 MyBatis

6.1 目标

   adminMapper 通过 IOC 容器装配到当前组件中后,就可以直接调用它的方法,享受 到框架给我们提供的方便
03-环境搭建_第13张图片

6.2 思路

03-环境搭建_第14张图片

6.3 操作清单

在子工程中加入搭建环境所需要的具体依赖
准备 jdbc.properties
创建 Spring 配置文件专门配置 Spring 和 MyBatis 整合相关
在 Spring 的配置文件中加载 jdbc.properties 属性文件
配置数据源
测试从数据源中获取数据库连接
配置 SqlSessionFactoryBean

  • 装配数据源
  • 指定 XxxMapper.xml 配置文件的位置
  • 指定 MyBatis 全局配置文件的位置(可选)

配置 MapperScannerConfigurer
测试是否可以装配 XxxMapper 接口并通过这个接口操作数据库

6.4 操作步骤详解

6.4.1 在子工程中加入搭建环境所需的具体依赖
   子工程:选择 component 工程。原因是具体依赖和 component 工程相关。

  <!--Spring 依赖 --> <!--https://mvnrepository.com/artifact/org.springframework/spring-orm-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
</dependency> <!--https://mvnrepository.com/artifact/org.springframework/spring-webmvc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
</dependency> <!--https://mvnrepository.com/artifact/org.aspectj/aspectjweaver-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency> <!--https://mvnrepository.com/artifact/cglib/cglib-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
</dependency> <!--MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
</dependency>
<!--MyBatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
</dependency>
<!--MyBatis 与 Spring 整合 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
</dependency>
<!--MyBatis 分页插件 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
</dependency> <!--Spring 进行 JSON 数据转换依赖 -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>
<!--JSTL 标签库 -->
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
</dependency> <!--https://mvnrepository.com/artifact/com.google.code.gson/gson-->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

6.4.2 数据库连接信息
jdbc.properties
03-环境搭建_第15张图片

jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/project_crowd?useUnicode=true&characterEncoding=UTF-8
jdbc.driver=com.mysql.jdbc.Driver

6.4.3 mybatis-config.xml03-环境搭建_第16张图片

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

</configuration>

6.4.4 创建 spring-persist-mybatis.xml
03-环境搭建_第17张图片
6.4.5 Spring 具体配置:第一步 配置数据源
6.4.6 Spring 具体配置:第二步 配置 SqlSessionFactoryBean
6.4.7 Spring 具体配置:第三步 配置 MapperScannerConfigurer

<?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 http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!-- 加载外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
    </bean>
    <!-- 配置SqlSessionFactoryBean整合MyBatis -->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定MyBatis全局配置文件位置 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!-- 指定Mapper.xml配置文件位置 -->
        <property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
        <!-- 装配数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置MapperScannerConfigurer来扫描Mapper接口所在的包 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.atguigu.crowd.mapper"/>
    </bean>
</beans>

创建 Spring 的 Junit 测试类
03-环境搭建_第18张图片
atcrowdfunding02-admin-webui的pom添加依赖

<!-- junit测试 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
// 指定 Spring 给 Junit 提供的运行器类
// 指定 Spring 给 Junit 提供的运行器类
@RunWith(SpringJUnit4ClassRunner.class)
// 加载 Spring 配置文件的注解
@ContextConfiguration(locations = {"classpath:spring-persist-mybatis.xml"})
public class CrowdTest {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private AdminMapper adminMapper;
    @Test
    public void testDataSource() throws SQLException {
		//1.通过数据源对象获取数据源连接
        Connection connection = dataSource.getConnection();
		//2.打印数据库连接
        System.out.println(connection);
    }
    @Test
    public void testInsertAdmin() {
        Admin admin = new Admin(null, "tom", "123123", "汤姆", "[email protected]", null);
        int count = adminMapper.insert(admin);
        // 如果在实际开发中,所有想查看数值的地方都使用sysout方式打印,会给项目上线运行带来问题!
        // sysout本质上是一个IO操作,通常IO的操作是比较消耗性能的。如果项目中sysout很多,那么对性能的影响就比较大了。
        // 即使上线前专门花时间删除代码中的sysout,也很可能有遗漏,而且非常麻烦。
        // 而如果使用日志系统,那么通过日志级别就可以批量的控制信息的打印。
        System.out.println("受影响的行数="+count);
    }
}

6.5 小结

03-环境搭建_第19张图片

7 日志系统

7.1 重要意义

   系统在运行过程中出了问题就需要通过日志来进行排查,所以我们在上手任何新技 术的时候,都要习惯性的关注一下它是如何打印日志的。03-环境搭建_第20张图片

7.2 技术选型

7.2.1 总体介绍
03-环境搭建_第21张图片
7.2.2 不同日志系统的整合
03-环境搭建_第22张图片
03-环境搭建_第23张图片

7.3 具体操作

7.3.1 初始状态
   Spring 使用 commons-logging 日志包。打印的日志是下面这样的。不用细看, 截图放在这是为了和后面日志打印的情况对比。
03-环境搭建_第24张图片
7.3.2 atcrowdfunding03-admin-component加入依赖slf4j+logback

<!-- 日志 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
</dependency>

代码不变,日志情况是:
03-环境搭建_第25张图片
7.3.3 我们主动打印的日志
把查询到的 Admin 对象以日志的方式打印出来,代码如下:

@Test
public void testLog() {
    Admin admin=adminMapper.selectByPrimaryKey(1511);
    // 获取日志记录对象
    Logger logger=LoggerFactory.getLogger(CrowdTest.class);
    // 按照 Debug 级别打印日志
    logger.debug(admin.toString());

    // 2.根据不同日志级别打印日志
    logger.debug("Hello I am Debug level!!!");
    logger.debug("Hello I am Debug level!!!");
    logger.debug("Hello I am Debug level!!!");

    logger.info("Info level!!!");
    logger.info("Info level!!!");
    logger.info("Info level!!!");

    logger.warn("Warn level!!!");
    logger.warn("Warn level!!!");
    logger.warn("Warn level!!!");

    logger.error("Error level!!!");
    logger.error("Error level!!!");
    logger.error("Error level!!!");
}

   使用日志打印信息和使用 sysout 打印信息的区别: sysout 如果不删除,那么 执行到这里必然会打印;如果使用日志方式打印,可以通过日志级别控制信息是否打印
   效果03-环境搭建_第26张图片
   这里我们看到除了 Druid 数据源打印了两条日志,Spring 和 MyBatis 并没有通 过 slf4j 打印日志。所以下一步我们要考虑的就是如何将框架所使用的日志系统统 一到 slf4j。
7.3.4 更换框架的日志系统

  • 第一步:atcrowdfunding02-admin-webui排除 commons-logging
    这个时候如果运行程序会抛异常,因为我们把 Spring 依赖的 commons-logging 排除了, 而这个依赖是必须有的,不是可选的。
     <!-- junit测试 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
  </dependencies>
  • 第二步:atcrowdfunding03-admin-component加入转换包
<!-- 其他日志框架的中间转换包 -->
<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<!-- <dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>jul-to-slf4j</artifactId>
</dependency> -->

打印效果局部:
在这里插入图片描述
7.3.5 logback 配置文件
   logback 工作时的具体细节可以通过 logback.xml 来配置。
03-环境搭建_第27张图片

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
	<!-- 指定日志输出的位置 -->
	<appender name="STDOUT"
		class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<!-- 日志输出的格式 -->
			<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
			<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
		</encoder>
	</appender>
	
	<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
	<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
	<root level="DEBUG">
		<!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
		<appender-ref ref="STDOUT" />
	</root>

	<!-- 根据特殊需求指定局部日志级别 -->
	<logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
	
</configuration>

8 声明式事务

8.1 目标

   从事务角度:一个事务方法中包含的多个数据库操作,要么一起提交、要么一起回 滚。也就是说事务方法中的多个数据库操作,有任何一个失败,整个事务全部回滚。
   从声明式角度:由 Spring 来全面接管数据库事务。用声明式代替编程式。
03-环境搭建_第28张图片

8.2 思路

03-环境搭建_第29张图片

8.3 操作

8.3.1 atcrowdfunding03-admin-component加入 AOP 依赖包

<!--https://mvnrepository.com/artifact/org.aspectj/aspectjweaver-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>
<!--https://mvnrepository.com/artifact/cglib/cglib-->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
</dependency>

8.3.2 第一步:创建 Spring 配置文件
03-环境搭建_第30张图片
8.3.3 第二步:配置事务管理器
8.3.4 第三步:配置 AOP
8.3.5 第四步:配置事务属性

<?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"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
	<!-- 配置自动扫描的包:主要是为了把Service扫描到IOC容器中 -->
	<context:component-scan base-package="com.atguigu.crowd.service"/>
	<!-- 配置事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<!-- 装配数据源 -->
		<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 配置事务切面 -->
	<aop:config>
		<!-- 考虑到后面我们整合SpringSecurity,避免把UserDetailsService加入事务控制,让切入点表达式定位到ServiceImpl -->
		<aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointcut"/>
		<!-- 将切入点表达式和事务通知关联起来 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
	</aop:config>
	<!-- 配置事务通知 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<!-- 配置事务属性 -->
		<tx:attributes>
			<!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能够进行一定优化 -->
			<tx:method name="get*" read-only="true"/>
			<tx:method name="find*" read-only="true"/>
			<tx:method name="query*" read-only="true"/>
			<tx:method name="count*" read-only="true"/>
			<!-- 增删改方法:配置事务传播行为、回滚异常 -->
			<!-- 
				propagation属性:
					REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程上没有已经开启的事务,则自己开新事务。如果已经有了,那么就使用这个已有的事务。
						顾虑:用别人的事务有可能“被”回滚。
					REQUIRES_NEW:建议使用的值,表示不管当前线程上有没有事务,都要自己开事务,在自己的事务中运行。
						好处:不会受到其他事务回滚的影响。
			 -->
			<!-- 
				rollback-for属性:配置事务方法针对什么样的异常回滚
					默认:运行时异常回滚
					建议:编译时异常和运行时异常都回滚
			 -->
			<tx:method name="save*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="update*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="remove*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
			<tx:method name="batch*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
		</tx:attributes>
	</tx:advice>
	<jdbc:embedded-database id="dataSource"/>
</beans>

在这里插入图片描述
报警不用管他,启动加载到spring容器中能找到

在CrowdTest中添加测试类方法testTx

  • 第一步:在atcrowdfunding03-admin-component中添加接口和实现类

03-环境搭建_第31张图片

public interface AdminService {
	void saveAdmin(Admin admin);
}
@Service
public class AdminServiceImpl implements AdminService {
	@Autowired
	private AdminMapper adminMapper;
	public void saveAdmin(Admin admin) {
		adminMapper.insert(admin);
		// throw new RuntimeException();
	}
}
  • 第二步:在CrowdTest添加配置路径信息
@ContextConfiguration(locations = {"classpath:spring-persist-mybatis.xml","classpath:spring-persist-tx.xml"})
  • 第三步:在CrowdTest注入adminService
@Autowired
AdminService adminService;
  • 第四步:在CrowdTest添加方法testTx
 @Test
public void testTx() {
    Admin admin = new Admin(null, "jerry", "123456", "杰瑞", "[email protected]", null);
    adminService.saveAdmin(admin);
}

9 表述层工作机制

9.1 启动过程

03-环境搭建_第32张图片

9.2 访问过程

03-环境搭建_第33张图片

10 表述层环境搭建

10.1在atcrowdfunding03-admin-component加入依赖

   使用 SpringMVC 环境引入 spring-webmvc 依赖即可,同时可以把 spring-context 依赖 去掉,因为根据依赖的传递性,spring-webmvc 会依赖 spring-context。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
</dependency>

10.2在atcrowdfunding02-admin-webui配置web.xml

10.2.1ContextLoaderListener
作用:加载 Spring 的配置文件,根据 Spring 的配置文件初始化 IOC 容器。
10.2.2CharacterEncodingFilter
   解决 POST 请求的字符乱码问题。需要注意的是:在 web.xml 中存在多个 Filter 时,让这个 Filter 作为过滤器链中的第一个 Filter。
   request.setCharacterEncoding(encoding) 要求必须在所有request.getParameter(xxx)操作前面
  response.setCharacterEncoding(encoding)要求必须在所有 response.getWriter() 操作前面
   不满足这个顺序要求字符集设定无法生效 springDispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-web-mvc.xml 1 springDispatcherServlet *.html *.json

10.3请求扩展名

10.3.1*.html 扩展名

  • 举例
    http://localhost:8080/atcrowdfunding02-admin-webui/save/emp.html

  • 作用:伪静态
    表面上看起来是一个访问静态资源的请求,但是实际上是由 SpringMVC 交给 handler 来处理的动态资源。

    • 好处 1:有利于 SEO 优化
      让搜索引擎更容易找到我们的网站,有利于网站的推广
    • 好处 2:隐藏后端技术实现细节
      给黑客入侵系统增加难度
    • 好处 3:自动解决静态资源访问问题
      访问 a.png 本身不符合*.html 这个 url-pattern,和 SpringMVC 完全没 有关系,当前请求由 Tomcat 处理。
      如 果 url-pattern 映 射 了 “/”, 那 么 SpringMVC 中 还 需 要 配 置 DefaultServletHandler。
  • 缺陷:不符合 RESTFUL 风格

10.3.2*.json 扩展名

  • 提出问题
    03-环境搭建_第34张图片

  • 描述问题
    请求扩展名 http://localhost:8080/extra01-ajax/get/emp/by/ajax.html
    服务器端打算返回的数据:JSON 格式 二者不匹配!!!

  • 分析问题
    请求扩展名和响应体的数据格式不匹配!!!

  • 解决问题
    让请求扩展名和预计的响应体数据格式一致。
    http://localhost:8080/extra01-ajax/get/emp/by/ajax.json
    同时让 SpringMVC 在映射*.html 扩展名之外再映射*.json 扩展名,不然会 返回 404

10.4在atcrowdfunding02-admin-webui配置spring-web-mvc.xml

10.4.1导入名称空间
context
mvc
10.4.2创建 SpringMVC 扫描的包
在atcrowdfunding03-admin-component创建com.atguigu.crowd.mvc
10.4.3具体配置

<?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:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!-- 配置自动扫描的包:扫描handler -->
    <context:component-scan base-package="com.atguigu.crowd.mvc"/>
    <!-- 配置SpringMVC的注解驱动 -->
    <mvc:annotation-driven/>
    <!-- 配置视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 配置基于XML的异常映射 -->
    <bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!-- 配置异常类型和具体视图页面的对应关系 -->
        <property name="exceptionMappings">
            <props>
                <!-- key属性指定异常全类名 -->
                <!-- 标签体中写对应的视图(这个值要拼前后缀得到具体路径) -->
                <prop key="java.lang.Exception">system-error</prop>
            </props>
        </property>
    </bean>
</beans>

10.5页面上的 base 标签

10.5.1在atcrowdfunding02-admin-webui加入依赖

<!-- 引入Servlet容器中相关依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <scope>provided</scope>
</dependency>
<!-- JSP页面使用的依赖 -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <scope>provided</scope>
</dependency>

10.5.2作用
将页面上路径中的${pageContext.request.contextPath}部分提取到页面开头

10.5.3写法

<base href="http://${pageContext.request.serverName }:${pageContext.request.serverPort }${pageContext.request.contextPath }/"/>

10.5.4需要注意的点

  • base 标签必须写在 head 标签内部

  • base 标签必须在所有“带具体路径”的标签的前面

  • serverName 部分 EL 表达式和 serverPort 部分 EL 表达式之间必须写“:”

  • serverPort部分EL表达式和contextPath部分EL表达式之间绝对不能写“/”

    • 原因:contextPath 部分 EL 表达式本身就是“/”开头
    • 如果多写一个“/”会干扰 Cookie 的工作机制
  • serverPort 部分 EL 表达式后面必须写“/”

10.6初步测试

**10.6.1在atcrowdfunding03-admin-component创建包com.atguigu.crowd.mvc.handler类TestHandler **

@Controller
public class TestHandler {
    @Autowired
    private AdminService adminService;
    @RequestMapping("/test/ssm.html")
    public String testSsm(ModelMap modelMap) {
        List<Admin> adminList = adminService.getAll();
        modelMap.addAttribute("adminList", adminList);
        return "target";
    }
}

AdminService添加方法

List<Admin> getAll();

AdminServiceImpl实现

public List<Admin> getAll() {
	return adminMapper.selectByExample(new AdminExample());
}

10.6.3在atcrowdfunding02-admin-webui创建目标 JSP 页面(视图)
创建index.jsp和targer.jsp页面
03-环境搭建_第35张图片

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- http://localhost:8080/atcrowdfunding02-admin-webui/test/ssm.html -->
<base href="http://${pageContext.request.serverName }:${pageContext.request.serverPort }${pageContext.request.contextPath }/"/>
</head>
<body>
	<a href="test/ssm.html">测试SSM整合环境</a>
</body>
</html>

targer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Success</h1>
	${requestScope.adminList }
</body>
</html>

启动测试
10.6.4友情提示
   跟着视频学习项目开发,表面上的现象错综复杂,   一会儿在页面,一会儿写 jQuery,一会儿写 handler,一会儿写 Service,一会儿写 SQL,一会儿写配置文件。
   背后有思路作为一根红线把所有的现象都穿起来,跟着思路走,就不会迷路。
   思路的背后是目标。
   思维一定要有层次!! !
03-环境搭建_第36张图片

11 SpringMVC 环境下的 Ajax 请求

11.1建立意识

前端发送过来,后端要处理的请求有两种:

  • 普通请求:后端处理完成后返回页面,浏览器使用使用页面替换整个窗口中的 内容
  • Ajax 请求:后端处理完成后通常返回 JSON 数据,jQuery 代码使用 JSON 数据 对页面局部更新

11.2测试

11.2.1加入 jQuery
03-环境搭建_第37张图片

index.jsp中引入jquery

<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>

11.3@ResponseBody 注解

11.3.1作用
  让 handler 方法的返回值本身就是当前请求的响应数据。不再参考视图处理器 中配置的前后缀信息。
11.3.2注意

  • 开启 SpringMVC 的注解驱动
<mvc:annotation-driven/>
  • 必须有 jackson 依赖
    jackson-core
    jackson-databind
  • 扩展名需要和实际返回的数据格式一致
    响应体返回 JSON
    请求扩展名*.json
    web.xml 中 DispatcherServlet 必须映射*.json 扩展名

11.4@RequestBody 注解

11.4.1场景设定
在index.jsp中添加script

<script type="text/javascript">
	$(function(){

	});
</script>

jQuery 通过 Ajax 请求给服务器端发送一个数组:[5,8,12]

11.4.2尝试方案一

  • 前端发送数据

中添加按钮

<br/>
<br/>
<button id="btn1">Send [5,8,12] One</button>

在function内添加请求

$.ajax({
	"url": "send/array/one.html",		// 请求目标资源的地址
	"type": "post",						// 请求方式
	"data": {							// 要发送的请求参数
		"array": [5,8,12]
	},
	"dataType": "text",					// 如何对待服务器端返回的数据
	"success": function(response) {		// 服务器端成功处理请求后调用的回调函数,response是响应体数据
		alert(response);
	},
	"error":function(response) {		// 服务器端处理请求失败后调用的回调函数,response是响应体数据
		alert(response);
	}
});
  • 浏览器开发者工具看到的请求体
    03-环境搭建_第38张图片
    jQuery 私自在请求参数名字后面附加了“[]”
  • 后端接收数据
    @RequestMapping("/send/array/one.html")
    这里一定要带上多出来的方括号!! !
    结论:不建议采用这个方案!!

在TestHandler添加方法,测试

@ResponseBody
@RequestMapping("/send/array/one.html")
public String testReceiveArrayOne(@RequestParam("array[]") List<Integer> array) {
    for (Integer number : array) {
        System.out.println("number="+number);
    }
    return "success";
}

11.4.3尝试方案二
前端发送数据
中添加按钮

<br/>
<br/>
<button id="btn2">Send [5,8,12] Two</button>

在function内添加请求

$("#btn2").click(function(){
	$.ajax({
		"url": "send/array/two.html",			// 请求目标资源的地址
		"type": "post",						// 请求方式
		"data": {							// 要发送的请求参数
			"array[0]": 5,
			"array[1]": 8,
			"array[2]": 12
		},
		"dataType": "text",					// 如何对待服务器端返回的数据
		"success": function(response) {		// 服务器端成功处理请求后调用的回调函数,response是响应体数据
			alert(response);
		},
		"error":function(response) {		// 服务器端处理请求失败后调用的回调函数,response是响应体数据
			alert(response);
		}
	});
});
  • 浏览器开发者工具看到的请求体
    在这里插入图片描述
  • 后端接收数据
    @RequestMapping("/send/array/two.html")
    在atcrowdfunding04-admin-entity创建实体类ParamData
 public class ParamData {
	private List<Integer> array;
	public ParamData() {
	}
	public ParamData(List<Integer> array) {
		super();
		this.array = array;
	}
	@Override
	public String toString() {
		return "ParamData [array=" + array + "]";
	}
	public List<Integer> getArray() {
		return array;
	}
	public void setArray(List<Integer> array) {
		this.array = array;
	}
}

在TestHandler添加方法,测试

@ResponseBody
@RequestMapping("/send/array/two.html")
public String testReceiveArrayTwo(ParamData paramData) {
    List<Integer> array = paramData.getArray();
    for (Integer number : array) {
        System.out.println("number="+number);
    }
    return "success";
}

11.4.3尝试方案三
前端发送数据
中添加按钮

<br/>
<br/>
<button id="btn3">Send [5,8,12] Three</button>

在function内添加请求

$("#btn3").click(function(){
	// 准备好要发送到服务器端的数组
	var array = [5, 8, 12];
	console.log(array.length);
	// 将JSON数组转换为JSON字符串
	var requestBody = JSON.stringify(array);
	// "['5','8','12']"
	console.log(requestBody.length);
	$.ajax({
		"url": "send/array/three.html",			// 请求目标资源的地址
		"type": "post",						// 请求方式
		"data": requestBody,				// 请求体
		"contentType": "application/json;charset=UTF-8",	// 设置请求体的内容类型,告诉服务器端本次请求的请求体是JSON数据
		"dataType": "text",					// 如何对待服务器端返回的数据
		"success": function(response) {		// 服务器端成功处理请求后调用的回调函数,response是响应体数据
			alert(response);
		},
		"error":function(response) {		// 服务器端处理请求失败后调用的回调函数,response是响应体数据
			alert(response);
		}
	});
});
  • 浏览器开发者工具看到的请求体
    在这里插入图片描述

  • 后端接收数据
    @RequestMapping("/send/array/three.html")

  • 在TestHandler添加方法,测试

@ResponseBody
@RequestMapping("/send/array/three.html")
public String testReceiveArrayThree(@RequestBody List<Integer> array) {
    for (Integer number : array) {
        logger.info("number="+number);
    }
    return "success";
}
  • 结论:建议使用的方案!!!

11.4.6发送复杂对象举例

  • 前端发送数据

中添加按钮

<br/>
<br/>
<button id="btn4">Send Compose Object</button>

在function内添加请求

$("#btn4").click(function(){
	// 准备要发送的数据
	var student = {
		"stuId": 5,
		"stuName":"tom",
		"address": {
			"province": "广东",
			"city": "深圳",
			"street":"后瑞"
		},
		"subjectList": [
			{
				"subjectName": "JavaSE",
				"subjectScore": 100
			},{
				"subjectName": "SSM",
				"subjectScore": 99
			}
		],
		"map": {
			"k1":"v1",
			"k2":"v2"
		}
	};
	// 将JSON对象转换为JSON字符串
	var requestBody = JSON.stringify(student);
	// 发送Ajax请求
	$.ajax({
		"url":"send/compose/object.json",
		"type":"post",
		"data":requestBody,
		"contentType":"application/json;charset=UTF-8",
		"dataType":"json",
		"success":function(response){
			console.log(response);
		},
		"error":function(response){
			console.log(response);
		}
	});
});
  • 浏览器开发者工具看到的请求体
    03-环境搭建_第39张图片
  • 后端接收数据
    @RequestMapping("/send/array/three.html")
    在atcrowdfunding05-common-util添加依赖
 <!-- 引入Servlet容器中相关依赖 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>

创建两个工具类
03-环境搭建_第40张图片
CrowdUtil

public class CrowdUtil {
	/**
	 * 判断当前请求是否为Ajax请求
	 * @param request 请求对象
	 * @return
	 * 		true:当前请求是Ajax请求
	 * 		false:当前请求不是Ajax请求
	 */
	public static boolean judgeRequestType(HttpServletRequest request) {
		
		// 1.获取请求消息头
		String acceptHeader = request.getHeader("Accept");
		String xRequestHeader = request.getHeader("X-Requested-With");
		
		// 2.判断
		return (acceptHeader != null && acceptHeader.contains("application/json"))
				
				||
				
				(xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
	}
}

ResultEntity

public class ResultEntity<T> {
	public static final String SUCCESS = "SUCCESS";
	public static final String FAILED = "FAILED";
	// 用来封装当前请求处理的结果是成功还是失败
	private String result;
	// 请求处理失败时返回的错误消息
	private String message;
	// 要返回的数据
	private T data;
	/**
	 * 请求处理成功且不需要返回数据时使用的工具方法
	 * @return
	 */
	public static <Type> ResultEntity<Type> successWithoutData() {
		return new ResultEntity<Type>(SUCCESS, null, null);
	}
	/**
	 * 请求处理成功且需要返回数据时使用的工具方法
	 * @param data 要返回的数据
	 * @return
	 */
	public static <Type> ResultEntity<Type> successWithData(Type data) {
		return new ResultEntity<Type>(SUCCESS, null, data);
	}
	/**
	 * 请求处理失败后使用的工具方法
	 * @param message 失败的错误消息
	 * @return
	 */
	public static <Type> ResultEntity<Type> failed(String message) {
		return new ResultEntity<Type>(FAILED, message, null);
	}
	public ResultEntity() {
	}
	public ResultEntity(String result, String message, T data) {
		super();
		this.result = result;
		this.message = message;
		this.data = data;
	}
	@Override
	public String toString() {
		return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
	}
	public String getResult() {
		return result;
	}
	public void setResult(String result) {
		this.result = result;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
}
  • 在TestHandler添加方法,测试
    在atcrowdfunding03-admin-component引入依赖
<!-- 引入Servlet容器中相关依赖 -->
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>servlet-api</artifactId>
	<version>2.5</version>
	<scope>provided</scope>
</dependency>
@ResponseBody
@RequestMapping("/send/compose/object.json")
public ResultEntity<Student> testReceiveComposeObject(@RequestBody Student student, HttpServletRequest request) {
    boolean judgeResult = CrowdUtil.judgeRequestType(request);
    logger.info("judgeResult="+judgeResult);
    logger.info(student.toString());
    // 将“查询”到的Student对象封装到ResultEntity中返回
    ResultEntity<Student> resultEntity = ResultEntity.successWithData(student);
    String a = null;
    System.out.println(a.length());
    return resultEntity;
}

11.4.7小结
  @RequestBody 使用的场景:传统发送请求参数方式不方便发送的数据,使用 JSON 请求体的方式发送。特别是要发送复杂对象的时候。

11.5对比

03-环境搭建_第41张图片

11.6统一返回数据格式

前面的工具类

你可能感兴趣的:(03-环境搭建)