一、配置数据库信息
1. 新建数据库与表
在数据库服务器中新建数据库和表。
2. 配置 jdbc 信息
在 src/main/resources
新建 jdbc.properties
文件,并配置数据库信息:
jdbc.username=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/nl_crowd_funding
jdbc.driver=com.mysql.jdbc.Driver
3. 配置数据源
在 src/main/resources
新建 applicationContext.xml
文件,并配置数据源:
<!-- 加载 jdbc 配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源 -->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
</bean>
这里需要在 pom.xml
引入 mysql-connector-java
、 druid
/ c3p0
依赖:
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.jdbc.version}</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
4. 测试 Spring 能否获取数据库连接
在 src/test/java
下新建 com.nigream.crowfunding.test.TestDataSource.java
类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:applicationContext.xml" })
public class TestDataSource {
@Autowired
private DataSource dataSource;
@Test
public void testConn() throws SQLException {
Connection connection = dataSource.getConnection();
System.out.println(connection);
}
}
这里需要引入如下依赖:
JUnit
: 用于单元测试。spring-test
: 用于整合Spring
与JUnit
,使用@RunWith
与@ContextConfiguration
注解。spring-beans
: 使用@Autowired
注解。spring-context
: 使用@ContextConfiguration
需要spring-context
的支持;。
<!-- 测试工具 ========================================================== -->
<!-- junit 测试(引入 hamcrest-core、junit ) -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- spring-test(引入 core 与 test ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- Spring 框架 ========================================================== -->
<!-- spring-beans(引入 beans、core ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring-context(引入 context、beans、expression、core 与 aop ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
若输出没问题,即可进入下一步。
二、整合 MyBatis
1. MyBatis 逆向工程
注意:建议另建 Maven 项目执行逆向工程,避免因操作失误覆盖掉重要文件。逆向工程可以生成
实体类
、*Example.java
、*Mapper.java
、*mapper.xml
文件。
在 src/main/resources
下,新建 generator-config.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>
<properties resource="jdbc.properties" />
<!-- mybatis-generator:generate -->
<context id="DBTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是;false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="${jdbc.driver}"
connectionURL="${jdbc.url}" userId="${jdbc.username}"
password="${jdbc.password}">
</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.nigream.crowdfunding.entity">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:XxxMapper.xml 映射文件生成的路径 -->
<sqlMapGenerator targetProject=".\src\main\resources"
targetPackage="mybatis/mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:Mapper 接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetProject=".\src\main\java"
targetPackage="com.nigream.crowdfunding.mapper">
<!-- enableSubPackages:是否让 schema 作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 数据库表名字和我们的 entity 类对应的映射指定 -->
<table tableName="t_admin" domainObjectName="Admin" />
</context>
</generatorConfiguration>
1.1 方法一
在 pom.xml
中引入如下依赖与配置:
<dependencies>
<!-- 持久层相关 -->
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>${mybatis-generator.version}</version>
<dependencies>
<!-- jdbc -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>${mybatis-generator.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
右击 pom.xml
,点击 Run as
下的 Maven Build...
,在 Goals
中输入 mybatis-generator:generate
,点击 Run
即可生成相应文件,将生成的文件移回原项目即可。
1.2 方法二
将 generator-config.xml
移动到 项目根目录
下,通过如下代码来生成文件:
public class MBGTest {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generator-config.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
但要在这样引入依赖:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- jdbc -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- 逆向工程 -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>${mybatis-generator.version}</version>
</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
中加入如下配置:
<!-- 配置SqlSessionFactoryBean用于Spring与MyBatis整合 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置MapperScannerConfigurer扫描Mapper接口所在的包 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
<property name="basePackage" value="com.nigream.crowdfunding.mapper"/>
</bean>
这里需要引入如下依赖:
MyBatis
mybatis-spring
: MyBatis 与 Spring 整合,使用 SqlSessionFactoryBean 读取 MyBatis 配置文件和 mapper 文件。spring-jdbc
: 整合 MyBatis 时需要,没有的话,下面的测试会报错。
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- MyBatis 与 Spring 整合 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!-- spring-jdbc(引入 beans、core 与 tx 与 jdbc ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
3. 测试 Mybatis 是否整合成功
在 TestDataSource.java
中,添加如下代码并执行,若数据库成功保存代码,即可视为 Mybatis 整合成功。
@Autowired
private AdminMapper adminMapper;
@Test
public void testInsert() throws SQLException {
Admin admin = new Admin(null, "jerry", "123456", "杰瑞", "jerry@gmail.com", null);
adminMapper.insertSelective(admin);
}
三、两种日志系统
有两种常用配置:
1. 使用 log4j
引入以下依赖:
<!-- slf4j:日志系统的接口 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<!-- log4j的适配器 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
在 src/main/resources
下新建 log4j.properties
进行配置:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
# 包消息级别
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=src/main/resources/log.txt
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# 输出消息编码 GB2312
log4j.appender.LOGFILE.encoding=UTF-8
2. 使用 logBack
2.1 排除 commons-logging
注意:不排除也可以用,嫌麻烦可以不进行这步。
首先引入如下依赖:
<!-- spring-core(引入 core,core 依赖于 commons-logging ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
因为这里直接依赖了 spring-core
,根据依赖传递的 就近优先原则
,其他 jar包
依赖的 spring-core
都不会传入,所以只要 spring-core
本身排除了commons-logging
依赖,就不会再有其他包传入该依赖。
2.2 使用 jcl
引入如下依赖:
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- slf4j 的实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- jcl 替换掉 Spring 自带的 commons-logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${jcl.version}</version>
</dependency>
在 src/main/resources
下新建 logback.xml
进行配置:
<?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.nigream.crowdfunding.dao" level="DEBUG" />
</configuration>
四、声明式事务
1. 配置
引入以下依赖:
<!-- 业务层 ========================================================== -->
<!-- spring-aop(引入 beans、core 与 aop ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<!-- aspectjweaver:负责切点织入 spring-aop需要依赖此包 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- spring-tx:事务控制(引入 beans、core 与 tx ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
在 applicationContext.xml
中加入如下内容:
<!-- 配置自动扫描的包:为了将Service扫描到IOC容器中 -->
<context:component-scan base-package="com.nigream.crowdfunding.service"/>
<!-- 配置事务管理器 -->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager" >
<!-- 装配数据源:只要spring-persist-mybatis.xml也加载了,就能使用这个数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice transaction-manager="transactionManager" id="txAdvice">
<tx:attributes>
<!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能进行一定优化。 -->
<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
<!-- 增删改方法:配置事务传播行为、回滚异常 -->
<!--
propagation属性:
REQUIRED:默认值,表示当前方法必须工作在事务中,如果当前线程上没有已经开启的事务,则自己开新事务;如果已有事务,就使用这个已有事务。(别的方法回滚他也会回滚)
REQUIRED_NEW:不管当前线程上有没有已经开启的事务,都要自己开事务,在自己新开的事务中运行。(不受其他事务回滚的影响)
-->
<!--
rollback-fors属性:配置事务方法针对什么样的异常回滚
默认:运行时异常回滚
建议:编译时异常和运行时异常都回滚
-->
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="remove*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="batch*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 定位到以ServiceImpl结尾的类中的方法 -->
<aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
2. 测试
在 src/main/java
的 com.nigream.crowdfunding.service.api
下新建并编辑 AdminService.java
:
public interface AdminService {
void saveOne(Admin admin);
}
在 src/main/java
的 com.nigream.crowdfunding.service.impl
下新建并编辑 AdminServiceImpl.java
:
@Service
public class AdminServiceImpl implements AdminService {
@Autowired
AdminMapper adminMapper;
@Override
public void saveOne(Admin admin) {
adminMapper.insertSelective(admin);
}
}
在 TestDataSource.java
中加入如下代码:
@Autowired
private AdminService adminService;
@Test
public void testSave() {
Admin admin = new Admin(null, "tom", "123456", "汤姆", "tom@gmail.com", null);
adminService.saveOne(admin);
}
若成功保存数据,则可进入下一步。
五、整合 Spring MVC
1. web.xml
引入依赖:
<!-- controller 层 ========================================================== -->
<!-- spring-webmvc(引入 context、beans、expression、core 与 aop、web、webmvc ) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
在 web.xml
中加入:
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<init-param>
<!-- 强制响应和请求设置字符集 -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<!-- 在所有Filter前执行,所以要放在所有Filter前 -->
<!-- 因为 request.setCharacterEncoding(encoding);必须要在request.getParameter()前面执行;
response.setCharacterEncoding(encoding);必须要在response.getWriter()前面执行; -->
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- Servlet默认生命周期中,创建对象是在第一次接收到请求时 -->
<!-- DispatcherServlet创建对象后有大量的“框架初始化”工作,不适合在第一次请求时来做 -->
<!-- 设置load-on-startup就是为了让DispatcherServlet在Web应用启动时创建对象、初始化 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- psot 转换成 delete 或 put -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 使put请求可以封装数据 -->
<filter>
<filter-name>httpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. springmvc.xml
在 src/main/resources
下新建 springmvc.xml
文件:
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.nigream.crowdfunding.controller"/>
<!-- 配置SpringMVC的注解驱动 -->
<mvc:annotation-driven/>
<!-- 处理静态资源 -->
<mvc:default-servlet-handler />
<!-- 配置视图解析器 -->
<!-- 将jsp文件放在WEB-INF目录下保护起来 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
3. 测试(以 .jsp 为例)
引入如下依赖:
<!-- 引入 Servlet 容器中相关依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- JSP 页面使用的依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
在 /webapp
目录下新建 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>
</head>
<body>
<a href="${pageContext.request.contextPath}/findAll">测试</a>
</body>
</html>
为了避免每次写链接都要带上 ${pageContext.request.contextPath}
,可以改成如下代码:
<%@ 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>
<base
href="http://${pageContext.request.serverName }:${pageContext.request.serverPort }${pageCon
text.request.contextPath }/"/>
<!-- 这里必须加上/,否则拼接不上 -->
</head>
<body>
<!-- 这里必须加上/,否则不会引用 <base/>里的内容 -->
<a href="/findAll">测试</a>
</body>
</html>
在 /webapp/WEB-INF/views
目录下新建 target.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>
在 AdminService
和 AdminServiceImpl
的类中添加 findAll
方法。
在 com.nigream.crowdfunding.controller
下新建 TestController.java
:
@Controller
public class TestController {
@Autowired
private AdminService adminService;
@RequestMapping("/findAll")
public String testSSM(ModelMap modelMap) {
modelMap.addAttribute("adminList",adminService.findAll());
return "target";
}
}
访问 http://localhost:8080/findAll
,若无异常,则测试通过。
六、 Ajax
1. 准备
在 src/main/webapp
下放入 jQuery
文件,在前端页面引入 jQuery
JSON 数据转换需要 jackson
的支持:
<!-- JSON 数据转换 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
2. 数组传输(方法一)
js 代码
$.ajax({
"url": "array/one", // 请求目标资源的地址
"type": "post", // 请求方式
"data": { // 要发送的请求参数
"array": [5,8,12]
},
"dataType": "text", // 如何对待服务器端返回的数据
"success": function(response) { // 服务器端成功处理请求后调用的回调函数,response是响应体数据
alert(response);
},
"error":function(response) { // 服务器端处理请求失败后调用的回调函数,response是响应体数据
alert(response);
}
});
java 代码
@RequestMapping("array/one")
@ResponseBody
// 前端 JQuery 传 array 时,会使他变成 array[] ,后端用 @RequestParam("array[]") 可接收
public String testArrayOne(@RequestParam("array[]") int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
return "Success";
}
3. 数组传输(方法二)
js 代码
$.ajax({
"url": "array/two", // 请求目标资源的地址
"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);
}
});
java 代码
@RequestMapping("array/two")
@ResponseBody
public String testArrayTwo(ParamData paramData) {
List<Integer> array = paramData.getArray();
for (int i = 0; i < array.size(); i++) {
System.out.println(array.get(i));
}
return "Success";
}
public class ParamData {
private List<Integer> array;
public ParamData() {
super();
}
public ParamData(List<Integer> array) {
super();
this.array = array;
}
public List<Integer> getArray() {
return array;
}
public void setArray(List<Integer> array) {
this.array = array;
}
@Override
public String toString() {
return "ParamData [array=" + array + "]";
}
}
4. 数组传输(方法三)
// 准备好要发送到服务器端的数组
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": "array/three", // 请求目标资源的地址
"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);
}
});
java 代码
@RequestMapping("array/three")
@ResponseBody
public String testArrayThree(@RequestBody List<Integer> array) {
for (int i = 0; i < array.size(); i++) {
System.out.println(array.get(i));
}
return "Success";
}
5. 传输复杂对象(统一返回的对象)
js 代码
// 准备要发送的数据
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":"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);
}
});
java 代码
/**
* 统一整个项目中Ajax请求返回的结果(未来也可以用于分布式架构各个模块间调用时返回统一类型)
*/
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;
}
}
@RequestMapping("compose/object")
@ResponseBody
public ResultEntity<Student> testReceiveComposeObject(@RequestBody Student student, HttpServletRequest request) {
// 将“查询”到的Student对象封装到ResultEntity中返回
ResultEntity<Student> resultEntity = ResultEntity.successWithData(student);
return resultEntity;
}
七、异常映射
1. 异常映射机制
两种请求:
两种处理方式:
注:springmvc.xml
中的 <mvc:view-controller path="/xxx/xxx" view-name-name="target"/>
配置,可以直接设置请求访问的视图。
2. 基于 XML 的异常映射
在 springmvc.xml
中插入如下配置,当出现异常,则会跳转到 system-error
页面:
<!-- 配置基于XML的异常映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="simpleMappingExceptionResolver">
<!-- 配置异常类型和具体视图页面的对应关系 -->
<property name="exceptionMappings">
<props>
<!-- key属性指定异常全类名 -->
<!-- 标签体中写对应的视图(这个值会拼前后缀得到具体路径) -->
<prop key="java.lang.Exception">system-error</prop>
</props>
</property>
</bean>
3. 判断请求类型
java 代码,在从 controller 方法中调用如下 judgeRequestType()
方法即可知道请求类型:
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"));
}
}
4. 基于注解的异常映射
// @ControllerAdvice表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {
@ExceptionHandler(value = ArithmeticException.class)
public ModelAndView resolveMathException(
ArithmeticException exception,
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
@ExceptionHandler(value = NullPointerException.class)
public ModelAndView resolveNullPointerException(
NullPointerException exception,
HttpServletRequest request,
HttpServletResponse response) throws IOException {
String viewName = "system-error";
return commonResolve(viewName, exception, request, response);
}
// @ExceptionHandler将一个具体的异常类型和一个方法关联起来
private ModelAndView commonResolve(
// 异常处理完成后要去的页面
String viewName,
// 实际捕获到的异常类型
Exception exception,
// 当前请求对象
HttpServletRequest request,
// 当前响应对象
HttpServletResponse response) throws IOException {
// 1.判断当前请求类型
boolean judgeResult = CrowdUtil.judgeRequestType(request);
// 2.如果是Ajax请求
if(judgeResult) {
// 3.创建ResultEntity对象
ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
// 4.创建Gson对象
Gson gson = new Gson();
// 5.将ResultEntity对象转换为JSON字符串
String json = gson.toJson(resultEntity);
// 6.将JSON字符串作为响应体返回给浏览器
response.getWriter().write(json);
// 7.由于上面已经通过原生的response对象返回了响应,所以不提供ModelAndView对象
return null;
}
// 8.如果不是Ajax请求则创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 9.将Exception对象存入模型
modelAndView.addObject("exception", exception);
// 10.设置对应的视图名称
modelAndView.setViewName(viewName);
// 11.返回modelAndView对象
return modelAndView;
}
}