项目结构
项目的构建
从原型创建
配置DarchetypeCatalog=internal
防止从网络获得项目配置
在Resource创建spring配置文件
<?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:mvc="http://www.springframework.org/schema/mvc"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启扫描 -->
<context:component-scan base-package="cn.landsall"/>
<!-- 视图解析器对象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图位置 -->
<property name="prefix" value="/WEB-INF/pages/"/>
<!-- 视图后缀名 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 开启SpringMvc框架注解的支持 -->
<mvc:annotation-driven/>
</beans>
配置前端控制器
在web.xml中
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 前端控制器加载spring配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- servlet在启动项目时就加载,且顺序为1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
配置不截拦静态资源
spring.xml
<mvc:resources location="/static/" mapping="/static/**"/>
Controller
RequestMapping注解
- 作用: 映射路径
- 可以放在类(一级目录)或方法(二级目录)上
- 注解属性
请求参数必须和JavaBean的属性对应
- JavaBean中有引用对象
绑定集合
绑定日期
自定义类型转换器
Spring对参数进行了自动的类型转换
如果要对日期等数据进行自定义转换
Convert接口
实现Convert接口
配置Spring.xml
返回值分类
返回视图
ModelAndView
响应ajax发送的值
发送零散的数据
- JS
发送数据时使用$form.serialize()
//#submit提交按钮
$("#submit").on('click', function (event) {
let $form = $("#login_form");
$.ajax({
url: "${pageContext.request.contextPath}/home/loginPost",
type: 'post',
data: $form.serialize(), //Jquery方法序列化表单为查询字符串
//contentType: "application/json;charset=UTF-8",
dataType: 'text',
success: function (data) {
if (data === "succeed")
location.href = "${pageContext.request.contextPath}/user/home"
else if (data === "failed")
alert("用户名或密码错误")
},
error: function () {
alert("服务器错误")
}
});
event.preventDefault();
});
控制器
@ResponseBody public String LoginPost(String username, String password, HttpSession httpSession) { User user = userService.userLogin(username, password); if (user != null) { httpSession.setAttribute("username", user.getUsername()); return "succeed"; } else { return "failed"; } }
发送JSON
将请求体封装为Java对象和将返回值封装为JSON,需要引入jackson
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.11.0</version> </dependency>
js
$("#submit").on('click', function (event) { let $form = $("#login_form"); let obj = {} //jquery方法serializeArray() //将表单数据序列化为name=value的数组 $.each($form.serializeArray(),function (index,data) { //将数据放入js对象 obj[data.name] = data.value; }) $.ajax({ url: "${pageContext.request.contextPath}/home/loginPost", type: 'post', data: JSON.stringify(obj), //Js原生方法 将JS对象序列化为JSON字符串 contentType: "application/json;charset=UTF-8", dataType: 'text', success: function (data) { if (data === "succeed") location.href = "${pageContext.request.contextPath}/user/home" else if (data === "failed") alert("用户名或密码错误") }, error: function () { alert("服务器错误") } }); event.preventDefault(); });
控制器
@ResponseBody public String LoginPost(@RequestBody User userPost, HttpSession httpSession) { User user = userService.userLogin(userPost.getUsername(), userPost.getPassword()); if (user != null) { httpSession.setAttribute("username", user.getUsername()); return "succeed"; } else { return "failed"; } }
serializeArray()序列化结果
上传文件
单服务器
- 引入jar包
```xml
commons-io commons-io 2.8.0
解析器->commons-fileupload->commons-io
- **配置文件解析器**
xml
- **控制器**

<a name="s4Dbw"></a>
### 跨服务器
- **引入jar包**
xml
- **控制器**

<a name="ueREw"></a>
# 过滤器和拦截器
<a name="qGNYp"></a>
## 拦截器
拦截器执行流程<br /><br />PreHandle返回true时,无论之后的结果afterCompletion都会执行<br />PreHandle返回false时,后续的截拦器和控制器方法都不会执行,浏览器返回空视图(通常会设置页面跳转)
- 创建类实现HandlerInterceptor
java
public class MyInterceptor implements HandlerInterceptor {
//控制器方法执行前(预处理)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(“preHandle 1 执行”);
return true;
}
//控制器方法执行后,视图解析前(后处理)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(“postHandle 1 执行”);
}
//在DispatcherServlet完全处理完请求之后被调用,可用于清理资源,日志打印
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(“afterCompletion 1 执行”);
}
}
- spring.xml配置拦截器
xml
预处理和后处理方法都可以指定页面跳转<br />
<a name="OTlvz"></a>
## Spring中的过滤器
<a name="gfNH2"></a>
### CharacterEncodingFilter
xml
<a name="dd38c9c5"></a>
# 异常处理
SpringMvc中的dao、service、controller出现异常都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。<br />
<a name="3mJcA"></a>
## Spring自带异常解析器
<a name="8NMlK"></a>
### SimpleMappingExceptionResolver
xml
<a name="AG0P8"></a>
## 自定义异常解析器
- 创建自定义异常类
- 实现**HandlerExceptionResolver**接口
java
//自定义异常解析器
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
BaseException ex = null;
if(e instanceof BaseException){
//如果是自定义异常则转换
ex = (BaseException)e;
//分别处理不同的异常
if(ex instanceof SysException){
modelAndView.setViewName(“Exception/SysException”);
}else if(ex instanceof UserException){
modelAndView.setViewName(“Exception/UserException”);
}
}else {
//系统异常
ex = new BaseException(e.getMessage());
modelAndView.setViewName(“Exception/UnKnowException”);
}
//返回异常信息
modelAndView.addObject(“message”,ex.getMessage());
//返回视图
return modelAndView;
}
}
``
- 配置自定义异常解析器

<a name="nMDLS"></a>
# 常用注解
<a name="DWtBy"></a>
### @RequestParam
- 指定参数绑定的名称,默认为必须传值

<a name="rGkFc"></a>
### @RequestBody
- 获得request请求体的值,对get请求不适用
- 常用在获取异步操作封装的值

<a name="r7UQp"></a>
### @ResponseBody
- 表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,而不是解析为跳转路径,一般在异步获取数据时使用
- 相当于 resp.getWriter().write();
- 如果控制器返回String,则Ajax接收text
- 如果控制器返回List,Map,单个对象等,则SpringMvc会自动封装为JSON(需要导入jackson)

<a name="3aPbp"></a>
### @PathVariable
- 将参数绑定到路径
- RESTful风格
- [http://www.ruanyifeng.com/blog/2014/05/restful_api.html](http://www.ruanyifeng.com/blog/2014/05/restful_api.html)

<a name="EVddr"></a>
### @RequestHeader
- 获取请求头的值(键值对)

<a name="uN9XJ"></a>
### @CookieValue
- 获取cookie中的值

<a name="yzCk2"></a>
### @ModelAttribute
- 绑定Model中的值
**应用**
1. 当表单提交的不是完整实体类时,确保没有提交的字段使用原来数据库的数据
- 有返回值时

- 无返回值时

<a name="Ve4A4"></a>
### @SessionAttributes
- 将
Model中的属性同步到
session会话当中
-
@SessionAttributes`设置的参数只用于*暂时的传递,而不是长期的保存,长期保存的数据还是要放到Session
中
- 配置在类上

详解:
https://cloud.tencent.com/developer/article/1497784
https://stackoverflow.com/questions/18791645/how-to-use-session-attributes-in-spring-mvc
@SessionAttributes 除了可以通过属性名指定需要放到会 话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中 例如: 1. @SessionAttributes(types=User.class)会将model中所有类型为 User的属性添加到会话中。 1. @SessionAttributes(value={“user1”, “user2”}) 会将model中属性名为user1和user2的属性添加到会话中。 1. @SessionAttributes(types={User.class, Dept.class}) 会将model中所有类型为 User和Dept的属性添加到会话中。 1. @SessionAttributes(value={“user1”,“user2”},types={Dept.class})会将model中属性名为user1和user2以及类型为Dept的属性添加到会话中。 # SSM整合
xml
<!--ssm-->
<dependency>
<groupId>org.singledog</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.3</version>
</dependency>
## 项目构建
- maven
```xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--ssm-->
<dependency>
<groupId>org.singledog</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.3</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!--jsp-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
</dependency>
<!--jstl-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--junit4-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
- web.xml
加载Spring配置文件<br />加载Springmvc配置文件<br />配置前端控制器<br />中文乱码过滤器
```xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<!-- Spring监听器,默认加载WEB-INF目录下的applicationContext.xml配置文件 -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 设置配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 前端控制器加载spring配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
<!-- servlet在启动项目时就加载,且顺序为1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 解决中文乱码的过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- springmvc-config.xml
扫描控制器
配置视图解析器
静态资源
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 扫描 Controller -->
<context:component-scan base-package="cn.landsall">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 视图解析器对象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 视图位置 -->
<property name="prefix" value="/WEB-INF/pages/"/>
<!-- 视图后缀名 -->
<property name="suffix" value=".jsp"/>
</bean>
<!-- 不截拦静态资源 -->
<mvc:resources location="/static/" mapping="/static/**"/>
<!-- 开启SpringMvc框架注解的支持 -->
<mvc:annotation-driven/>
</beans>
- spring-config.xml
扫描 Spring 和 Mybatis
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/cache"
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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<!-- 开启扫描,不处理 SpringMvc-->
<context:component-scan base-package="cn.landsall">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://111.229.166.200:3306/ssm?serverTimezone=Asia/Shanghai" />
<property name="username" value="admin" />
<property name="password" value="cyl032512" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="20" />
</bean>
<!-- 配置 SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 实体类别名 -->
<property name="typeAliasesPackage" value="cn.landsall.entity"/>
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:/mapper/*.xml"/>
</bean>
<!-- 配置 映射器 所在的包 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.landsall.dao"/>
</bean>
</beans>
pagehelper 分页
github: https://github.com/pagehelper/Mybatis-PageHelper
文档: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/README_zh.md
API: https://apidoc.gitee.com/free/Mybatis_PageHelper/
实现原理: https://www.w3cschool.cn/mybatis/mybatis-ypsj3bpi.html
视频 : https://www.bilibili.com/video/BV1mE411X7yp?p=302
- 5.X.X 版本
https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
- 集成SpringMvc
https://github.com/abel533/Mybatis-Spring
引入依赖jar包
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.X.X</version>
</dependency>
配置分页拦截器
参数
mybatis
mybatis-config.xml
<plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql"/> <!-- 该参数默认为false --> <!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 --> <!-- 和startPage中的pageNum效果一样--> <property name="offsetAsPageNum" value="true"/> <!-- 该参数默认为false --> <!-- 设置为true时,使用RowBounds分页会进行count查询 --> <property name="rowBoundsWithCount" value="true"/> <!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 --> <!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型) <property name="pageSizeZero" value="true"/>--> <!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 --> <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 --> <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 --> <property name="reasonable" value="true"/> <!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 --> <!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 --> <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 --> <!-- 不理解该含义的前提下,不要随便复制该配置 <property name="params" value="pageNum=start;pageSize=limit;"/> --> </plugin> </plugins>
ssm
<!-- 配置 SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 实体类别名 --> <property name="typeAliasesPackage" value="cn.landsall.entity"/> <!-- 分页插件 --> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <props> <prop key="helperDialect">mysql</prop> <prop key="reasonable">true</prop> </props> </property> </bean> </array> </property> </bean>
使用
在执行查询语句前调用静态方法
PageHelper.startPage(currentPage,pageSize); List<Book> list = bookService.getAll();
案例
BookList.jsp ```html
<td><a href="${pageContext.request.contextPath}/book/detail/${book.id}">${book.bookName}</a></td> <td>${book.author}</td> <td>${book.publish}</td> <td><fmt:formatDate value="${book.publish_time}" pattern="yyyy-MM-dd"/></td> <td>${book.ISBN}</td> <td>${book.desc}</td> <td colspan="2"> <a href="${pageContext.request.contextPath}/book/update/${book.id}">修改</a> <a href="${pageContext.request.contextPath}/book/del/${book.id}">删除</a> </td>
总条数 ${pageinfo.total} , 共 ${pageinfo.pages} 页 , 每页 条
- Controller.java
```java
@RequestMapping("/list/{currentPage}/{pageSize}")
public String List(ModelMap modelMap, @PathVariable int currentPage, @PathVariable int pageSize) {
pageSize = pageSize > MinPageSize ? pageSize : MinPageSize;
PageHelper.startPage(currentPage, pageSize);
List<Book> list = bookService.getAll();
PageInfo<Book> pageInfo = new PageInfo<>(list);
//导航条逻辑
int startPage = pageInfo.getPageNum();
int subPage = (startPage % PageRange + PageRange - 1)%PageRange;
startPage -= subPage;
int endPage = startPage + PageRange - 1;
endPage = Math.min(endPage, pageInfo.getPages());
modelMap.addAttribute("startPage", startPage);
modelMap.addAttribute("endPage", endPage);
modelMap.addAttribute("pageinfo", pageInfo);
return "BookList";
}