一、配置数据库信息

1. 新建数据库与表

在数据库服务器中新建数据库和表。

2. 配置 jdbc 信息

src/main/resources 新建 jdbc.properties 文件,并配置数据库信息:

  1. jdbc.username=root
  2. jdbc.password=root
  3. jdbc.url=jdbc:mysql://localhost:3306/nl_crowd_funding
  4. jdbc.driver=com.mysql.jdbc.Driver

3. 配置数据源

src/main/resources 新建 applicationContext.xml 文件,并配置数据源:

  1. <!-- 加载 jdbc 配置文件 -->
  2. <context:property-placeholder location="classpath:jdbc.properties"/>
  3. <!-- 配置数据源 -->
  4. <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
  5. <property name="username" value="${jdbc.username}"/>
  6. <property name="password" value="${jdbc.password}"/>
  7. <property name="url" value="${jdbc.url}"/>
  8. <property name="driverClassName" value="${jdbc.driver}"/>
  9. </bean>

这里需要在 pom.xml 引入 mysql-connector-javadruid / c3p0 依赖:

  1. <!-- MySQL 驱动 -->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. <version>${mysql.jdbc.version}</version>
  6. </dependency>
  7. <!-- 数据源 -->
  8. <dependency>
  9. <groupId>com.alibaba</groupId>
  10. <artifactId>druid</artifactId>
  11. <version>${druid.version}</version>
  12. </dependency>

4. 测试 Spring 能否获取数据库连接

src/test/java 下新建 com.nigream.crowfunding.test.TestDataSource.java 类:

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(locations = { "classpath:applicationContext.xml" })
  3. public class TestDataSource {
  4. @Autowired
  5. private DataSource dataSource;
  6. @Test
  7. public void testConn() throws SQLException {
  8. Connection connection = dataSource.getConnection();
  9. System.out.println(connection);
  10. }
  11. }

这里需要引入如下依赖:

  • JUnit : 用于单元测试。
  • spring-test : 用于整合 SpringJUnit ,使用 @RunWith@ContextConfiguration 注解。
  • spring-beans : 使用 @Autowired 注解。
  • spring-context : 使用 @ContextConfiguration 需要 spring-context 的支持;。
  1. <!-- 测试工具 ========================================================== -->
  2. <!-- junit 测试(引入 hamcrest-core、junit ) -->
  3. <dependency>
  4. <groupId>junit</groupId>
  5. <artifactId>junit</artifactId>
  6. <version>${junit.version}</version>
  7. <scope>test</scope>
  8. </dependency>
  9. <!-- spring-test(引入 core 与 test ) -->
  10. <dependency>
  11. <groupId>org.springframework</groupId>
  12. <artifactId>spring-test</artifactId>
  13. <version>${spring.version}</version>
  14. <scope>test</scope>
  15. </dependency>
  16. <!-- Spring 框架 ========================================================== -->
  17. <!-- spring-beans(引入 beans、core ) -->
  18. <dependency>
  19. <groupId>org.springframework</groupId>
  20. <artifactId>spring-beans</artifactId>
  21. <version>${spring.version}</version>
  22. </dependency>
  23. <!-- spring-context(引入 context、beans、expression、core 与 aop ) -->
  24. <dependency>
  25. <groupId>org.springframework</groupId>
  26. <artifactId>spring-context</artifactId>
  27. <version>${spring.version}</version>
  28. </dependency>

若输出没问题,即可进入下一步。

二、整合 MyBatis

1. MyBatis 逆向工程

注意:建议另建 Maven 项目执行逆向工程,避免因操作失误覆盖掉重要文件。逆向工程可以生成 实体类*Example.java*Mapper.java*mapper.xml 文件。

src/main/resources 下,新建 generator-config.xml 文件,进行如下配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6. <properties resource="jdbc.properties" />
  7. <!-- mybatis-generator:generate -->
  8. <context id="DBTables" targetRuntime="MyBatis3">
  9. <commentGenerator>
  10. <!-- 是否去除自动生成的注释 true:是;false:否 -->
  11. <property name="suppressAllComments" value="true" />
  12. </commentGenerator>
  13. <!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
  14. <jdbcConnection driverClass="${jdbc.driver}"
  15. connectionURL="${jdbc.url}" userId="${jdbc.username}"
  16. password="${jdbc.password}">
  17. </jdbcConnection>
  18. <!-- 默认 false,把 JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true 时把 JDBC DECIMAL
  19. 和 NUMERIC 类型解析为 java.math.BigDecimal -->
  20. <javaTypeResolver>
  21. <property name="forceBigDecimals" value="false" />
  22. </javaTypeResolver>
  23. <!-- targetProject:生成 Entity 类的路径 -->
  24. <javaModelGenerator targetProject=".\src\main\java"
  25. targetPackage="com.nigream.crowdfunding.entity">
  26. <!-- enableSubPackages:是否让 schema 作为包的后缀 -->
  27. <property name="enableSubPackages" value="false" />
  28. <!-- 从数据库返回的值被清理前后的空格 -->
  29. <property name="trimStrings" value="true" />
  30. </javaModelGenerator>
  31. <!-- targetProject:XxxMapper.xml 映射文件生成的路径 -->
  32. <sqlMapGenerator targetProject=".\src\main\resources"
  33. targetPackage="mybatis/mapper">
  34. <!-- enableSubPackages:是否让 schema 作为包的后缀 -->
  35. <property name="enableSubPackages" value="false" />
  36. </sqlMapGenerator>
  37. <!-- targetPackage:Mapper 接口生成的位置 -->
  38. <javaClientGenerator type="XMLMAPPER"
  39. targetProject=".\src\main\java"
  40. targetPackage="com.nigream.crowdfunding.mapper">
  41. <!-- enableSubPackages:是否让 schema 作为包的后缀 -->
  42. <property name="enableSubPackages" value="false" />
  43. </javaClientGenerator>
  44. <!-- 数据库表名字和我们的 entity 类对应的映射指定 -->
  45. <table tableName="t_admin" domainObjectName="Admin" />
  46. </context>
  47. </generatorConfiguration>

1.1 方法一

pom.xml 中引入如下依赖与配置:

  1. <dependencies>
  2. <!-- 持久层相关 -->
  3. <!-- Mybatis -->
  4. <dependency>
  5. <groupId>org.mybatis</groupId>
  6. <artifactId>mybatis</artifactId>
  7. <version>${mybatis.version}</version>
  8. </dependency>
  9. </dependencies>
  10. <build>
  11. <plugins>
  12. <plugin>
  13. <groupId>org.mybatis.generator</groupId>
  14. <artifactId>mybatis-generator-maven-plugin</artifactId>
  15. <version>${mybatis-generator.version}</version>
  16. <dependencies>
  17. <!-- jdbc -->
  18. <dependency>
  19. <groupId>mysql</groupId>
  20. <artifactId>mysql-connector-java</artifactId>
  21. <version>${mysql.version}</version>
  22. </dependency>
  23. <!-- 数据库连接池 -->
  24. <dependency>
  25. <groupId>com.mchange</groupId>
  26. <artifactId>c3p0</artifactId>
  27. <version>${c3p0.version}</version>
  28. </dependency>
  29. <!-- 逆向工程 -->
  30. <dependency>
  31. <groupId>org.mybatis.generator</groupId>
  32. <artifactId>mybatis-generator-core</artifactId>
  33. <version>${mybatis-generator.version}</version>
  34. </dependency>
  35. </dependencies>
  36. </plugin>
  37. </plugins>
  38. </build>

右击 pom.xml ,点击 Run as 下的 Maven Build... ,在 Goals 中输入 mybatis-generator:generate ,点击 Run 即可生成相应文件,将生成的文件移回原项目即可。

1.2 方法二

generator-config.xml 移动到 项目根目录 下,通过如下代码来生成文件:

  1. public class MBGTest {
  2. public static void main(String[] args) throws Exception {
  3. // TODO Auto-generated method stub
  4. List<String> warnings = new ArrayList<String>();
  5. boolean overwrite = true;
  6. File configFile = new File("generator-config.xml");
  7. ConfigurationParser cp = new ConfigurationParser(warnings);
  8. Configuration config = cp.parseConfiguration(configFile);
  9. DefaultShellCallback callback = new DefaultShellCallback(overwrite);
  10. MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
  11. myBatisGenerator.generate(null);
  12. }
  13. }

但要在这样引入依赖:

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>${mybatis.version}</version>
  5. </dependency>
  6. <!-- jdbc -->
  7. <dependency>
  8. <groupId>mysql</groupId>
  9. <artifactId>mysql-connector-java</artifactId>
  10. <version>${mysql.version}</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.mchange</groupId>
  14. <artifactId>c3p0</artifactId>
  15. <version>${c3p0.version}</version>
  16. </dependency>
  17. <!-- 逆向工程 -->
  18. <dependency>
  19. <groupId>org.mybatis.generator</groupId>
  20. <artifactId>mybatis-generator-core</artifactId>
  21. <version>${mybatis-generator.version}</version>
  22. </dependency>

2. 配置 applicationContext.xml

按如下要求准备好所需文件:

  • src/main/java 下的 com.nigream.crowdfunding.mapper : 放操作数据库的接口类。
  • src/main/java 下的 com.nigream.crowdfunding.entity : 放实体类。
  • src/main/resources 下的 mybatis/mapper : 放 mapper 配置文件,以 Mapper.xml 结尾。
  • src/main/resources 下 : 放 mybatis-config.xml ,这里可以先不写内容。

applicationContext.xml 中加入如下配置:

  1. <!-- 配置SqlSessionFactoryBean用于Spring与MyBatis整合 -->
  2. <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
  3. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  4. <property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
  5. <property name="dataSource" ref="dataSource"/>
  6. </bean>
  7. <!-- 配置MapperScannerConfigurer扫描Mapper接口所在的包 -->
  8. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
  9. <property name="basePackage" value="com.nigream.crowdfunding.mapper"/>
  10. </bean>

这里需要引入如下依赖:

  • MyBatis
  • mybatis-spring : MyBatis 与 Spring 整合,使用 SqlSessionFactoryBean 读取 MyBatis 配置文件和 mapper 文件。
  • spring-jdbc : 整合 MyBatis 时需要,没有的话,下面的测试会报错。
  1. <!-- MyBatis -->
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>${mybatis.version}</version>
  6. </dependency>
  7. <!-- MyBatis 与 Spring 整合 -->
  8. <dependency>
  9. <groupId>org.mybatis</groupId>
  10. <artifactId>mybatis-spring</artifactId>
  11. <version>${mybatis-spring.version}</version>
  12. </dependency>
  13. <!-- spring-jdbc(引入 beans、core 与 tx 与 jdbc ) -->
  14. <dependency>
  15. <groupId>org.springframework</groupId>
  16. <artifactId>spring-jdbc</artifactId>
  17. <version>${spring.version}</version>
  18. </dependency>

3. 测试 Mybatis 是否整合成功

TestDataSource.java 中,添加如下代码并执行,若数据库成功保存代码,即可视为 Mybatis 整合成功。

  1. @Autowired
  2. private AdminMapper adminMapper;
  3. @Test
  4. public void testInsert() throws SQLException {
  5. Admin admin = new Admin(null, "jerry", "123456", "杰瑞", "jerry@gmail.com", null);
  6. adminMapper.insertSelective(admin);
  7. }

三、两种日志系统

有两种常用配置:

1. 使用 log4j

引入以下依赖:

  1. <!-- slf4j:日志系统的接口 -->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. </dependency>
  6. <!-- log4j -->
  7. <dependency>
  8. <groupId>org.apache.logging.log4j</groupId>
  9. <artifactId>log4j-core</artifactId>
  10. </dependency>
  11. <!-- log4j的适配器 -->
  12. <dependency>
  13. <groupId>org.slf4j</groupId>
  14. <artifactId>slf4j-log4j12</artifactId>
  15. </dependency>

src/main/resources 下新建 log4j.properties 进行配置:

  1. # Set root category priority to INFO and its only appender to CONSOLE.
  2. #log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
  3. # 包消息级别
  4. log4j.rootCategory=debug, CONSOLE, LOGFILE
  5. # Set the enterprise logger category to FATAL and its only appender to CONSOLE.
  6. log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
  7. # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
  8. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
  9. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
  10. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  11. # LOGFILE is set to be a File appender using a PatternLayout.
  12. log4j.appender.LOGFILE=org.apache.log4j.FileAppender
  13. log4j.appender.LOGFILE.File=src/main/resources/log.txt
  14. log4j.appender.LOGFILE.Append=true
  15. log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
  16. log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
  17. # 输出消息编码 GB2312
  18. log4j.appender.LOGFILE.encoding=UTF-8

2. 使用 logBack

2.1 排除 commons-logging

注意:不排除也可以用,嫌麻烦可以不进行这步。

首先引入如下依赖:

  1. <!-- spring-core(引入 core,core 依赖于 commons-logging ) -->
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-core</artifactId>
  5. <version>${spring.version}</version>
  6. <exclusions>
  7. <exclusion>
  8. <groupId>commons-logging</groupId>
  9. <artifactId>commons-logging</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>

因为这里直接依赖了 spring-core ,根据依赖传递的 就近优先原则 ,其他 jar包 依赖的 spring-core 都不会传入,所以只要 spring-core 本身排除了commons-logging 依赖,就不会再有其他包传入该依赖。

2.2 使用 jcl

引入如下依赖:

  1. <!-- slf4j -->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. <version>${slf4j.version}</version>
  6. </dependency>
  7. <!-- slf4j 的实现 -->
  8. <dependency>
  9. <groupId>ch.qos.logback</groupId>
  10. <artifactId>logback-classic</artifactId>
  11. <version>${logback.version}</version>
  12. </dependency>
  13. <!-- jcl 替换掉 Spring 自带的 commons-logging -->
  14. <dependency>
  15. <groupId>org.slf4j</groupId>
  16. <artifactId>jcl-over-slf4j</artifactId>
  17. <version>${jcl.version}</version>
  18. </dependency>

src/main/resources 下新建 logback.xml 进行配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <configuration debug="true">
  3. <!-- 指定日志输出的位置 -->
  4. <appender name="STDOUT"
  5. class="ch.qos.logback.core.ConsoleAppender">
  6. <encoder>
  7. <!-- 日志输出的格式 -->
  8. <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体 内容、换行 -->
  9. <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
  10. </encoder>
  11. </appender>
  12. <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
  13. <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
  14. <root level="DEBUG">
  15. <!-- 指定打印日志的 appender,这里通过“STDOUT”引用了前面配置的 appender -->
  16. <appender-ref ref="STDOUT" />
  17. </root>
  18. <!-- 根据特殊需求指定局部日志级别 -->
  19. <logger name="com.nigream.crowdfunding.dao" level="DEBUG" />
  20. </configuration>

四、声明式事务

1. 配置

引入以下依赖:

  1. <!-- 业务层 ========================================================== -->
  2. <!-- spring-aop(引入 beans、core 与 aop ) -->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-aop</artifactId>
  6. </dependency>
  7. <!-- aspectjweaver:负责切点织入 spring-aop需要依赖此包 -->
  8. <dependency>
  9. <groupId>org.aspectj</groupId>
  10. <artifactId>aspectjweaver</artifactId>
  11. </dependency>
  12. <!-- spring-tx:事务控制(引入 beans、core 与 tx ) -->
  13. <dependency>
  14. <groupId>org.springframework</groupId>
  15. <artifactId>spring-tx</artifactId>
  16. </dependency>

applicationContext.xml 中加入如下内容:

  1. <!-- 配置自动扫描的包:为了将Service扫描到IOC容器中 -->
  2. <context:component-scan base-package="com.nigream.crowdfunding.service"/>
  3. <!-- 配置事务管理器 -->
  4. <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager" >
  5. <!-- 装配数据源:只要spring-persist-mybatis.xml也加载了,就能使用这个数据源 -->
  6. <property name="dataSource" ref="dataSource"/>
  7. </bean>
  8. <tx:advice transaction-manager="transactionManager" id="txAdvice">
  9. <tx:attributes>
  10. <!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能进行一定优化。 -->
  11. <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
  12. <!-- 增删改方法:配置事务传播行为、回滚异常 -->
  13. <!--
  14. propagation属性:
  15. REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程上没有已经开启的事务,则自己开新事务;如果已有事务,就使用这个已有事务。(别的方法回滚他也会回滚)
  16. REQUIRED_NEW:不管当前线程上有没有已经开启的事务,都要自己开事务,在自己新开的事务中运行。(不受其他事务回滚的影响)
  17. -->
  18. <!--
  19. rollback-fors属性:配置事务方法针对什么样的异常回滚
  20. 默认:运行时异常回滚
  21. 建议:编译时异常和运行时异常都回滚
  22. -->
  23. <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
  24. <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
  25. <tx:method name="remove*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
  26. <tx:method name="batch*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
  27. <tx:method name="*"/>
  28. </tx:attributes>
  29. </tx:advice>
  30. <aop:config>
  31. <!-- 定位到以ServiceImpl结尾的类中的方法 -->
  32. <aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointCut"/>
  33. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
  34. </aop:config>

2. 测试

src/main/javacom.nigream.crowdfunding.service.api 下新建并编辑 AdminService.java

  1. public interface AdminService {
  2. void saveOne(Admin admin);
  3. }

src/main/javacom.nigream.crowdfunding.service.impl 下新建并编辑 AdminServiceImpl.java

  1. @Service
  2. public class AdminServiceImpl implements AdminService {
  3. @Autowired
  4. AdminMapper adminMapper;
  5. @Override
  6. public void saveOne(Admin admin) {
  7. adminMapper.insertSelective(admin);
  8. }
  9. }

TestDataSource.java 中加入如下代码:

  1. @Autowired
  2. private AdminService adminService;
  3. @Test
  4. public void testSave() {
  5. Admin admin = new Admin(null, "tom", "123456", "汤姆", "tom@gmail.com", null);
  6. adminService.saveOne(admin);
  7. }

若成功保存数据,则可进入下一步。

五、整合 Spring MVC

1. web.xml

引入依赖:

  1. <!-- controller 层 ========================================================== -->
  2. <!-- spring-webmvc(引入 context、beans、expression、core 与 aop、web、webmvc ) -->
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-webmvc</artifactId>
  6. <version>${spring.version}</version>
  7. </dependency>

web.xml 中加入:

  1. <!-- needed for ContextLoaderListener -->
  2. <context-param>
  3. <param-name>contextConfigLocation</param-name>
  4. <param-value>classpath:applicationContext.xml</param-value>
  5. </context-param>
  6. <!-- Bootstraps the root web application context before servlet initialization -->
  7. <listener>
  8. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  9. </listener>
  10. <filter>
  11. <filter-name>characterEncodingFilter</filter-name>
  12. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  13. <init-param>
  14. <!-- 指定字符集 -->
  15. <param-name>encoding</param-name>
  16. <param-value>UTF-8</param-value>
  17. </init-param>
  18. <init-param>
  19. <!-- 强制响应和请求设置字符集 -->
  20. <param-name>forceEncoding</param-name>
  21. <param-value>true</param-value>
  22. </init-param>
  23. </filter>
  24. <filter-mapping>
  25. <!-- 在所有Filter前执行,所以要放在所有Filter前 -->
  26. <!-- 因为 request.setCharacterEncoding(encoding);必须要在request.getParameter()前面执行;
  27. response.setCharacterEncoding(encoding);必须要在response.getWriter()前面执行; -->
  28. <filter-name>characterEncodingFilter</filter-name>
  29. <url-pattern>/*</url-pattern>
  30. </filter-mapping>
  31. <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
  32. <servlet>
  33. <servlet-name>springDispatcherServlet</servlet-name>
  34. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  35. <init-param>
  36. <param-name>contextConfigLocation</param-name>
  37. <param-value>classpath:springmvc.xml</param-value>
  38. </init-param>
  39. <!-- Servlet默认生命周期中,创建对象是在第一次接收到请求时 -->
  40. <!-- DispatcherServlet创建对象后有大量的“框架初始化”工作,不适合在第一次请求时来做 -->
  41. <!-- 设置load-on-startup就是为了让DispatcherServlet在Web应用启动时创建对象、初始化 -->
  42. <load-on-startup>1</load-on-startup>
  43. </servlet>
  44. <!-- Map all requests to the DispatcherServlet for handling -->
  45. <servlet-mapping>
  46. <servlet-name>springDispatcherServlet</servlet-name>
  47. <url-pattern>/</url-pattern>
  48. </servlet-mapping>
  49. <!-- psot 转换成 delete 或 put -->
  50. <filter>
  51. <filter-name>hiddenHttpMethodFilter</filter-name>
  52. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  53. </filter>
  54. <filter-mapping>
  55. <filter-name>hiddenHttpMethodFilter</filter-name>
  56. <url-pattern>/*</url-pattern>
  57. </filter-mapping>
  58. <!-- 使put请求可以封装数据 -->
  59. <filter>
  60. <filter-name>httpPutFormContentFilter</filter-name>
  61. <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
  62. </filter>
  63. <filter-mapping>
  64. <filter-name>httpPutFormContentFilter</filter-name>
  65. <url-pattern>/*</url-pattern>
  66. </filter-mapping>

2. springmvc.xml

src/main/resources 下新建 springmvc.xml 文件:

  1. <!-- 配置自动扫描的包 -->
  2. <context:component-scan base-package="com.nigream.crowdfunding.controller"/>
  3. <!-- 配置SpringMVC的注解驱动 -->
  4. <mvc:annotation-driven/>
  5. <!-- 处理静态资源 -->
  6. <mvc:default-servlet-handler />
  7. <!-- 配置视图解析器 -->
  8. <!-- 将jsp文件放在WEB-INF目录下保护起来 -->
  9. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
  10. <property name="prefix" value="/WEB-INF/views/"/>
  11. <property name="suffix" value=".jsp"/>
  12. </bean>

3. 测试(以 .jsp 为例)

引入如下依赖:

  1. <!-- 引入 Servlet 容器中相关依赖 -->
  2. <dependency>
  3. <groupId>javax.servlet</groupId>
  4. <artifactId>servlet-api</artifactId>
  5. <version>${servlet.version}</version>
  6. <scope>provided</scope>
  7. </dependency>
  8. <!-- JSP 页面使用的依赖 -->
  9. <dependency>
  10. <groupId>javax.servlet.jsp</groupId>
  11. <artifactId>jsp-api</artifactId>
  12. <version>${jsp.version}</version>
  13. <scope>provided</scope>
  14. </dependency>

/webapp 目录下新建 index.jsp

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <meta charset="UTF-8">
  7. <title>Insert title here</title>
  8. </head>
  9. <body>
  10. <a href="${pageContext.request.contextPath}/findAll">测试</a>
  11. </body>
  12. </html>

为了避免每次写链接都要带上 ${pageContext.request.contextPath} ,可以改成如下代码:

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <meta charset="UTF-8">
  7. <title>Insert title here</title>
  8. <base
  9. href="http://${pageContext.request.serverName }:${pageContext.request.serverPort }${pageCon
  10. text.request.contextPath }/"/>
  11. <!-- 这里必须加上/,否则拼接不上 -->
  12. </head>
  13. <body>
  14. <!-- 这里必须加上/,否则不会引用 <base/>里的内容 -->
  15. <a href="/findAll">测试</a>
  16. </body>
  17. </html>

/webapp/WEB-INF/views 目录下新建 target.jsp

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <meta charset="UTF-8">
  7. <title>Insert title here</title>
  8. </head>
  9. <body>
  10. <h1>Success</h1>
  11. ${requestScope.adminList}
  12. </body>
  13. </html>

AdminServiceAdminServiceImpl 的类中添加 findAll 方法。

com.nigream.crowdfunding.controller 下新建 TestController.java

  1. @Controller
  2. public class TestController {
  3. @Autowired
  4. private AdminService adminService;
  5. @RequestMapping("/findAll")
  6. public String testSSM(ModelMap modelMap) {
  7. modelMap.addAttribute("adminList",adminService.findAll());
  8. return "target";
  9. }
  10. }

访问 http://localhost:8080/findAll ,若无异常,则测试通过。

六、 Ajax

1. 准备

src/main/webapp 下放入 jQuery 文件,在前端页面引入 jQuery

JSON 数据转换需要 jackson 的支持:

  1. <!-- JSON 数据转换 -->
  2. <dependency>
  3. <groupId>com.fasterxml.jackson.core</groupId>
  4. <artifactId>jackson-core</artifactId>
  5. <version>${jackson.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>com.fasterxml.jackson.core</groupId>
  9. <artifactId>jackson-databind</artifactId>
  10. <version>${jackson.version}</version>
  11. </dependency>

2. 数组传输(方法一)

js 代码

  1. $.ajax({
  2. "url": "array/one", // 请求目标资源的地址
  3. "type": "post", // 请求方式
  4. "data": { // 要发送的请求参数
  5. "array": [5,8,12]
  6. },
  7. "dataType": "text", // 如何对待服务器端返回的数据
  8. "success": function(response) { // 服务器端成功处理请求后调用的回调函数,response是响应体数据
  9. alert(response);
  10. },
  11. "error":function(response) { // 服务器端处理请求失败后调用的回调函数,response是响应体数据
  12. alert(response);
  13. }
  14. });

java 代码

  1. @RequestMapping("array/one")
  2. @ResponseBody
  3. // 前端 JQuery 传 array 时,会使他变成 array[] ,后端用 @RequestParam("array[]") 可接收
  4. public String testArrayOne(@RequestParam("array[]") int[] array) {
  5. for (int i = 0; i < array.length; i++) {
  6. System.out.println(array[i]);
  7. }
  8. return "Success";
  9. }

3. 数组传输(方法二)

js 代码

  1. $.ajax({
  2. "url": "array/two", // 请求目标资源的地址
  3. "type": "post", // 请求方式
  4. "data": { // 要发送的请求参数
  5. "array[0]": 5,
  6. "array[1]": 8,
  7. "array[2]": 12
  8. },
  9. "dataType": "text", // 如何对待服务器端返回的数据
  10. "success": function(response) { // 服务器端成功处理请求后调用的回调函数,response是响应体数据
  11. alert(response);
  12. },
  13. "error":function(response) { // 服务器端处理请求失败后调用的回调函数,response是响应体数据
  14. alert(response);
  15. }
  16. });

java 代码

  1. @RequestMapping("array/two")
  2. @ResponseBody
  3. public String testArrayTwo(ParamData paramData) {
  4. List<Integer> array = paramData.getArray();
  5. for (int i = 0; i < array.size(); i++) {
  6. System.out.println(array.get(i));
  7. }
  8. return "Success";
  9. }
  1. public class ParamData {
  2. private List<Integer> array;
  3. public ParamData() {
  4. super();
  5. }
  6. public ParamData(List<Integer> array) {
  7. super();
  8. this.array = array;
  9. }
  10. public List<Integer> getArray() {
  11. return array;
  12. }
  13. public void setArray(List<Integer> array) {
  14. this.array = array;
  15. }
  16. @Override
  17. public String toString() {
  18. return "ParamData [array=" + array + "]";
  19. }
  20. }

4. 数组传输(方法三)

  1. // 准备好要发送到服务器端的数组
  2. var array = [5, 8, 12];
  3. console.log(array.length);
  4. // 将JSON数组转换为JSON字符串
  5. var requestBody = JSON.stringify(array);
  6. // "['5','8','12']"
  7. console.log(requestBody.length);
  8. $.ajax({
  9. "url": "array/three", // 请求目标资源的地址
  10. "type": "post", // 请求方式
  11. "data": requestBody, // 请求体
  12. "contentType": "application/json;charset=UTF-8", // 设置请求体的内容类型,告诉服务器端本次请求的请求体是JSON数据
  13. "dataType": "text", // 如何对待服务器端返回的数据
  14. "success": function(response) { // 服务器端成功处理请求后调用的回调函数,response是响应体数据
  15. alert(response);
  16. },
  17. "error":function(response) { // 服务器端处理请求失败后调用的回调函数,response是响应体数据
  18. alert(response);
  19. }
  20. });

java 代码

  1. @RequestMapping("array/three")
  2. @ResponseBody
  3. public String testArrayThree(@RequestBody List<Integer> array) {
  4. for (int i = 0; i < array.size(); i++) {
  5. System.out.println(array.get(i));
  6. }
  7. return "Success";
  8. }

5. 传输复杂对象(统一返回的对象)

js 代码

  1. // 准备要发送的数据
  2. var student = {
  3. "stuId": 5,
  4. "stuName":"tom",
  5. "address": {
  6. "province": "广东",
  7. "city": "深圳",
  8. "street":"后瑞"
  9. },
  10. "subjectList": [
  11. {
  12. "subjectName": "JavaSE",
  13. "subjectScore": 100
  14. },{
  15. "subjectName": "SSM",
  16. "subjectScore": 99
  17. }
  18. ],
  19. "map": {
  20. "k1":"v1",
  21. "k2":"v2"
  22. }
  23. };
  24. // 将JSON对象转换为JSON字符串
  25. var requestBody = JSON.stringify(student);
  26. // 发送Ajax请求
  27. $.ajax({
  28. "url":"compose/object.json",
  29. "type":"post",
  30. "data":requestBody,
  31. "contentType":"application/json;charset=UTF-8",
  32. "dataType":"json",
  33. "success":function(response){
  34. console.log(response);
  35. },
  36. "error":function(response){
  37. console.log(response);
  38. }
  39. });

java 代码

  1. /**
  2. * 统一整个项目中Ajax请求返回的结果(未来也可以用于分布式架构各个模块间调用时返回统一类型)
  3. */
  4. public class ResultEntity<T> {
  5. public static final String SUCCESS = "SUCCESS";
  6. public static final String FAILED = "FAILED";
  7. // 用来封装当前请求处理的结果是成功还是失败
  8. private String result;
  9. // 请求处理失败时返回的错误消息
  10. private String message;
  11. // 要返回的数据
  12. private T data;
  13. /**
  14. * 请求处理成功且不需要返回数据时使用的工具方法
  15. * @return
  16. */
  17. public static <Type> ResultEntity<Type> successWithoutData() {
  18. return new ResultEntity<Type>(SUCCESS, null, null);
  19. }
  20. /**
  21. * 请求处理成功且需要返回数据时使用的工具方法
  22. * @param data 要返回的数据
  23. * @return
  24. */
  25. public static <Type> ResultEntity<Type> successWithData(Type data) {
  26. return new ResultEntity<Type>(SUCCESS, null, data);
  27. }
  28. /**
  29. * 请求处理失败后使用的工具方法
  30. * @param message 失败的错误消息
  31. * @return
  32. */
  33. public static <Type> ResultEntity<Type> failed(String message) {
  34. return new ResultEntity<Type>(FAILED, message, null);
  35. }
  36. public ResultEntity() {
  37. }
  38. public ResultEntity(String result, String message, T data) {
  39. super();
  40. this.result = result;
  41. this.message = message;
  42. this.data = data;
  43. }
  44. @Override
  45. public String toString() {
  46. return "ResultEntity [result=" + result + ", message=" + message + ", data=" + data + "]";
  47. }
  48. public String getResult() {
  49. return result;
  50. }
  51. public void setResult(String result) {
  52. this.result = result;
  53. }
  54. public String getMessage() {
  55. return message;
  56. }
  57. public void setMessage(String message) {
  58. this.message = message;
  59. }
  60. public T getData() {
  61. return data;
  62. }
  63. public void setData(T data) {
  64. this.data = data;
  65. }
  66. }
  1. @RequestMapping("compose/object")
  2. @ResponseBody
  3. public ResultEntity<Student> testReceiveComposeObject(@RequestBody Student student, HttpServletRequest request) {
  4. // 将“查询”到的Student对象封装到ResultEntity中返回
  5. ResultEntity<Student> resultEntity = ResultEntity.successWithData(student);
  6. return resultEntity;
  7. }

七、异常映射

1. 异常映射机制

两种请求:

两种处理方式:

注:springmvc.xml 中的 <mvc:view-controller path="/xxx/xxx" view-name-name="target"/> 配置,可以直接设置请求访问的视图。

2. 基于 XML 的异常映射

springmvc.xml 中插入如下配置,当出现异常,则会跳转到 system-error 页面:

  1. <!-- 配置基于XML的异常映射 -->
  2. <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="simpleMappingExceptionResolver">
  3. <!-- 配置异常类型和具体视图页面的对应关系 -->
  4. <property name="exceptionMappings">
  5. <props>
  6. <!-- key属性指定异常全类名 -->
  7. <!-- 标签体中写对应的视图(这个值会拼前后缀得到具体路径) -->
  8. <prop key="java.lang.Exception">system-error</prop>
  9. </props>
  10. </property>
  11. </bean>

3. 判断请求类型

java 代码,在从 controller 方法中调用如下 judgeRequestType() 方法即可知道请求类型:

  1. public class CrowdUtil {
  2. /**
  3. * 判断当前请求是否为Ajax请求
  4. * @param request 请求对象
  5. * @return
  6. * true:当前请求是Ajax请求
  7. * false:当前请求不是Ajax请求
  8. */
  9. public static boolean judgeRequestType(HttpServletRequest request) {
  10. // 1.获取请求消息头
  11. String acceptHeader = request.getHeader("Accept");
  12. String xRequestHeader = request.getHeader("X-Requested-With");
  13. // 2.判断
  14. return (acceptHeader != null && acceptHeader.contains("application/json"))
  15. ||
  16. (xRequestHeader != null && xRequestHeader.equals("XMLHttpRequest"));
  17. }
  18. }

4. 基于注解的异常映射

  1. // @ControllerAdvice表示当前类是一个基于注解的异常处理器类
  2. @ControllerAdvice
  3. public class CrowdExceptionResolver {
  4. @ExceptionHandler(value = ArithmeticException.class)
  5. public ModelAndView resolveMathException(
  6. ArithmeticException exception,
  7. HttpServletRequest request,
  8. HttpServletResponse response
  9. ) throws IOException {
  10. String viewName = "system-error";
  11. return commonResolve(viewName, exception, request, response);
  12. }
  13. @ExceptionHandler(value = NullPointerException.class)
  14. public ModelAndView resolveNullPointerException(
  15. NullPointerException exception,
  16. HttpServletRequest request,
  17. HttpServletResponse response) throws IOException {
  18. String viewName = "system-error";
  19. return commonResolve(viewName, exception, request, response);
  20. }
  21. // @ExceptionHandler将一个具体的异常类型和一个方法关联起来
  22. private ModelAndView commonResolve(
  23. // 异常处理完成后要去的页面
  24. String viewName,
  25. // 实际捕获到的异常类型
  26. Exception exception,
  27. // 当前请求对象
  28. HttpServletRequest request,
  29. // 当前响应对象
  30. HttpServletResponse response) throws IOException {
  31. // 1.判断当前请求类型
  32. boolean judgeResult = CrowdUtil.judgeRequestType(request);
  33. // 2.如果是Ajax请求
  34. if(judgeResult) {
  35. // 3.创建ResultEntity对象
  36. ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
  37. // 4.创建Gson对象
  38. Gson gson = new Gson();
  39. // 5.将ResultEntity对象转换为JSON字符串
  40. String json = gson.toJson(resultEntity);
  41. // 6.将JSON字符串作为响应体返回给浏览器
  42. response.getWriter().write(json);
  43. // 7.由于上面已经通过原生的response对象返回了响应,所以不提供ModelAndView对象
  44. return null;
  45. }
  46. // 8.如果不是Ajax请求则创建ModelAndView对象
  47. ModelAndView modelAndView = new ModelAndView();
  48. // 9.将Exception对象存入模型
  49. modelAndView.addObject("exception", exception);
  50. // 10.设置对应的视图名称
  51. modelAndView.setViewName(viewName);
  52. // 11.返回modelAndView对象
  53. return modelAndView;
  54. }
  55. }