Springmv+Spring+mybatis
🍓导包
Spring
的IOC
核心依赖4
个包Springmvc
的两个web
包Spring
的AOP
的4
个包Spring-JDBC
包mysql
数据库的依赖c3p0
数据库连接池的2
个依赖mybatis
的包和Spring
支持mybatis
的包- 前端可能会使用的
jstl
和jstl-api
以及standard
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.aopalliance/com.springsource.org.aopalliance-->
<dependency>
<groupId>org.aopalliance</groupId>
<artifactId>com.springsource.org.aopalliance</artifactId>
<version>1.0.0</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/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-tx-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--spring整合mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--返回json格式的数据-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
<!-- xml序列化工具,类似与JAXB,JAXB依赖jdk内部实现,这个功能更丰富 -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.12.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.4</version>
</dependency>
🍓创建配置文件
🍒db.properties数据库配置文件
- 数据库驱动
- 数据库访问
url
- 数据库用户名
- 数据库密码
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test8?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=cqrjxk39
注意:
在xml
中写数据库访问url
时,“&”
会变成"&"
,这可能是由xml
的编码规则决定的,在xml
文件中有以下几类字符要进行转义替换:
< | < | 小于号 |
---|---|---|
> | > | 大于号 |
& | & | 与 |
' | ’ | 单引号 |
" | " | 双引号 |
🍒mybatis-cfg配置
- 打印
sql
语句 - 实例类别名配置
<?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>
<!--打印日志-->
<settings>
<!-- 打印查询语句 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<!--指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,不区分大小写-->
<package name="com.spring.pojo"></package>
</typeAliases>
</configuration>
🍒application-context.xml配置
- 配置组件扫描,完成
bean
管理 - 加载配置文件
db.properties
- 配置
c3p0
数据库连接池 - 配置
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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">
<context:component-scan base-package="com.spring"></context:component-scan>
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mapperLocations" value="classpath:com/spring/dao/*.xml"></property>
<property name="configLocation" value="classpath:mybatis-cfg.xml"></property>
</bean>
<!--Spring配置mapper-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.spring.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
注意: 使用eclipse
编译器编写此段代码很容易会出现Cannot find the declaration of element 'beans'
这个错误,在这种情况下可以使用本地对象,如下:
<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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
classpath:/org/springframework/beans/factory/xml/spring-beans.xsd
http://www.springframework.org/schema/context
classpath:/org/springframework/context/config/spring-context.xsd
http://www.springframework.org/schema/tx
classpath:/org/springframework/transaction/config/spring-tx.xsd
http://www.springframework.org/schema/aop
classpath:/org/springframework/aop/config/spring-aop.xsd">
使用classpath:+
路径,路径去本地导入的jar
包中去找
🍒springmvc配置
- 配置注解驱动
- 视图解析器
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1.约束文件 -->
<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/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd ">
<!--注解驱动,使用注解驱动器可以加载处理器映射器RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--虽说在application-context.xml配置了注解扫描,但是还是有可能会扫不到@Controller,导致访问方法时出现404的错误,所以我们尽量在springmvc中再配一次针对controller包的扫描-->
<context:component-scan base-package="com.spring.controller"></context:component-scan>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--后缀-->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
🍒web.xml配置
- 配置
Spring
的监听器(用来读取配置文件application-context.xml
) - 配置前端控制器
- 配置
POST
提交编码格式(防止乱码)
<listener>
<!--web依赖下面的context包下的ContextLoaderListener-->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<!--配置前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--默认找/WEB-INF/[servlet的名称(springmvc)]-servlet.xml-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!--配置拦截规则
1. /* 拦截所有(jsp,js,png,css)
2. *.action *.do 拦截以do,action结尾的请求 (面向后台)
3. / 拦截所有(不包括jsp,其他都拦截) (面向前台)
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--防止前端传递过来的参数出现乱码,如果有乱码添加以下代码-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
🍒springmvc对静态资源处理
当web.xml
的拦截为“/”
或者“/*”
拦截所有的时候,前端的CSS
和js
等页面同样会被拦截,所以我们需要在springmvc.xml
配置中对静态资源做一定的处理
<mvc:resources location="/CSS/" mapping="/CSS/**"></mvc:resources>
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
🍓Springmvc转换日期格式或者字符串样式
在Springmvc
中配置转换工厂,转换器主要由springmvc
的适配器来完成
springmvc
配置文件配置
<!--注解驱动,使用注解驱动器可以加载处理器映射器RequestMappingHandlerMapping和处理器适配器RequestMappingHandlerAdapter-->
<mvc:annotation-driven conversion-service="ConversionServiceFactoryBean"></mvc:annotation-driven>
<!--配置Conveter转换器,转换工厂(日期格式、去掉前后空格)-->
<bean id="ConversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!--配置多个转换器-->
<property name="converters">
<list>
<!--自定义转换器-->
<bean class="com.spring.converter.DateConverter"></bean>
</list>
</property>
</bean>
自定义转换器,实现Converter
接口
import org.springframework.core.convert.converter.Converter;
//String为需要转换的目标的类型,Timestamp是被转换的目标类型
public class DateConverter implements Converter<String, Timestamp> {
@Override
public Timestamp convert(String s) {
try {
if( s != null){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy:MM-dd HH_mm-ss");
Timestamp parse = (Timestamp) simpleDateFormat.parse(s);
return parse;
}
}catch (Exception e){
}
return null;
}
}
🍓高阶参数绑定
🍒数组
数组大多应用于多选删除的场合
例如:
前端
<!--引入jstl的jar包,并且定义对象为c-->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<form action="${pageContext.request.contextPath}/deletes.action" method="post">
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemList }" var="item">
<tr>
<td><input type="checkbox" name="ids" value="${item.id}"></td>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
</table>
<input type="submit" value="删除">
</form>
后端:
//produces参数是为了防止后端传递给前端数据中有中文时会出现乱码
@RequestMapping(value = "/deletes.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8")
public String deletes(Integer[] ids){
for (Integer id:ids){
itemService.delete(id);
}
return "redirect:/itemList.action";
}
🍒list
list
集合一般用于批量修改
例如:
-
后端实体类中必须要有list集合,且泛型为该实体类
-
前端代码:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <form action="${pageContext.request.contextPath}/updates.action" method="post"> 商品列表: <table width="100%" border=1> <tr> <td>商品名称</td> <td>商品价格</td> <td>生产日期</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${itemList }" var="item" varStatus="s"> <tr> <td><input type="hidden" name="items[${s.index}].id" value="${item.id}"></td> <td><input type="text" name="items[${s.index}].name" value="${item.name }"></td> <td><input type="text" name="items[${s.index}].price" value="${item.price }"></td> <td><input type="text" name="items[${s.index}].detail" value="${item.detail }"></td> <td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td> </tr> </c:forEach> </table> <input type="submit" value="修改"> </form>
-
后端
@RequestMapping(value = "/updates.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8") public String updates(Item item){ List<Item> items = item.getItems(); for (int i= 0; i < items.size(); i++){ itemService.update(items.get(i)); } return "redirect:/itemList.action"; }
🍓springmvc的注解
-
@RequestMapping
:表示方法返回的是页面或者是重定向,可以放在方法上,也可以放在类上value
:访问路径,是数组,可以实现多请求,多个url
可以使用大括号括起来,值之间以“,”
隔开method
:提交方式,常用的两个值为RequestMethod.POST
和RequestMethod.GET
,默认值为get
,也是数组,支持多种提交方式也是用大括号括起来,值之间以“,”
隔开produces
:后端传递前端的参数格式,防止参数中含有中文会出现乱码问题
-
@ResponseBody
:一般与@RequestMapping
配套使用,返回json
数据 -
@RestController
:放在类上,相当于@ResponseBody+@Controller
,表示该类下所有的方法都返回的是json
数据 -
@CrossOrigin(allowCredentials="true", allowedHeaders="*")
:Spring4.2
及以上版本支持,放在类上,用于解决跨域问题。4.2
以下版本可以使用拦截器来解决跨域问题,文章下面讲述拦截器时有提到,里面的参数配合前端ajax
的属性xhrFields: {withCredentials: true}
,可以保证跨域请求获取sessionId
的一致性
🍓异常处理器(HandlerExceptionResolver)
springmvc
在处理请求过程中会负责捕获dao,service,controller
层的异常信息,并交由自定义异常处理器处理,异常分为预期异常(自己可以预测到的)和运行时异常(未知的)
-
创建预期异常类,并继承
Exception
类@Data public class MessageException extends Exception { private String msg; public MessageException(String msg){ this.msg = msg; } }
-
在
dao,service,controller
你能预测到可能会发生此异常的地方抛出此异常if(items == null){ throw new MessageException("商品信息不能为空"); }
-
创建自定义异常类,并实现
org.springframework.web.servlet.HandlerExceptionResolver
接口,并使用注解将其纳入spring
的bean
管理import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class ExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView modelAndView = new ModelAndView(); //判断异常类型 if(e instanceof MessageException){ //预期异常 MessageException messageException = (MessageException)e; modelAndView.addObject("error",(messageException.getMsg())); }else{ //运行时异常 modelAndView.addObject("error","未知异常"); System.out.println(o); System.out.println(e); } modelAndView.setViewName("error"); return modelAndView; } }
🍓上传文件
-
在
Deployment
创建文件夹upload
(名字随便取) -
配置
tomcat
-
添加文件上传依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency>
-
前端
- 不管你是上传图片还是上传文件,
form
表单的属性里面必须要有enctype="multipart/form-data"
- 设置回显时,必须要先判断,否则图片可能没有,显示不出来
- 不管你是上传图片还是上传文件,
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
<table width="100%" border=1>
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }" /></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${item.price }" /></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime"
value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
</tr>
<tr>
<td>商品图片</td>
<td>
<c:if test="${item.pid !=null}">
<!--判断图片是否存在,这边的路径必须与你在上面配置tomcat的路径一致-->
<img src="/pid/${item.pid}" width=100 height=100/>
<br/>
</c:if>
<input type="file" name="pictureFile"/>
</td>
</tr>
<tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
</td>
</tr>
</table>
</form>
- 后端
- 设置图片的名字
- 获取文件后缀名
- 保存到磁盘
- 保存到数据库(只需保存图片名即可,因为前端有配置完整的路径)
@RequestMapping(value = "/updateitem.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
public String updateitem(Item item, MultipartFile pictureFile) throws IOException {
// 设置图片名字,防止名字重复
String s = UUID.randomUUID().toString().replaceAll("-", "");
//获取文件扩展名
String extension = FilenameUtils.getExtension(pictureFile.getOriginalFilename());
// 保存图片到D盘
pictureFile.transferTo(new File("D:\\upload\\"+s+"."+extension));
//保存到数据库
item.setPid(s+"."+extension);
itemService.update(item);
return "redirect:/itemEdit.action?id="+item.getId();
}
🍓json数据交互
-
导入解析
json
数据的三个包<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.8</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.8</version> </dependency>
-
导入
jquery
-
前端
ajax
编写<head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>修改商品信息</title> <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.4.4.min.js"></script> <script type="text/javascript"> $(function () { // alert(1); var params = '{"id":10,"name":"测试商品","price":99.9,"detail":"测试商品描述","pid":"123456.jpg"}'; $.ajax({ url:"${pageContext.request.contextPath}/json.action", data:params, contentType:"application/json;charset=UTF-8",//发送的数据格式 type:"post", dataType:"json",//回调的数据也是json数据 success:function (data) { alert(data.name); } }) }) </script> </head>
-
创建一个类封装
json
数据 -
接收
json
数据,并返回json
数据到前端@ResponseBody @RequestMapping(value = "/json.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8") public Item json(@RequestBody Item item){ System.out.println("json来了"); System.out.println(item); return item; }
🍓RestFu的开发风格
如果前端的请求url
的方式如下所示,请求参数直接放在url
中,并没有使用?+键值对
的形式,那么后端的代码为
前端:
<td><a href="${pageContext.request.contextPath }/itemEdit/${item.id}.action">修改</a></td>
后端:
@RequestMapping(value = "/itemEdit/{id}.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8")
public String toEditItem(@PathVariable int id,Model model){
Item item = new Item();
item.setId(id);
List<Item> items = itemService.find(item);
if(items.size() != 0){
model.addAttribute("item",items.get(0));
}
return "editItem";
}
🍓拦截器
🍒访问顺序
用户访问——>拦截器方法前——>执行controller
层方法——>拦截器方法后——>拦截器页面渲染——>用户
🍒拦截器的使用
-
创建拦截器类,并实现
org.springframework.web.servlet.HandlerInterceptor
接口,可以创建多个import org.springframework.lang.Nullable; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Interceptor1 implements HandlerInterceptor { //方法前,true表示放行,false表示拦截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //Spring4.2以下版本解决跨域问题 String originHeader = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", originHeader); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "0"); response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("XDomainRequestAllowed","1"); response.setHeader("XDomainRequestAllowed","1"); return true; } //方法后 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } //页面渲染 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
-
在
springmvc
配置文件中配置拦截器<mvc:interceptors> <!--自定义拦截器,可以定义多个--> <mvc:interceptor> <!--/**指拦截所有--> <mvc:mapping path="/**"/> <bean class="com.spring.interceptor.Interceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <!--/**指拦截所有--> <mvc:mapping path="/**"/> <bean class="com.spring.interceptor.Interceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
🍒拦截器的执行流程
- 方法前
preHandle
按照拦截器定义的顺序调用 - 方法后
postHandle
按照拦截器定义的逆序调用,并且只有当方法前preHandle全部
返回true
才会调用 - 页面渲染
afterCompletion
按照拦截器定义的逆序调用,只要其所在的拦截器的方法前preHandle
返回true
就会调用
🍒实际操作
前端登录页面:
<form action="${pageContext.request.contextPath}/login.action" method="post">
<input type="text" name="username"><br />
<input type="submit" value="登录">
</form>
后端:
-
前往登录页面
-
登录后保存用户名到
session
,并跳转到其他页面//前往登录页面 @RequestMapping(value = "/login.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8") public String tologin(){ return "login"; } //登录后保存跳转 @RequestMapping(value = "/login.action",method = RequestMethod.POST,produces="text/html;charset=UTF-8") public String login(String username, HttpSession session){ //将用户名保存到session session.setAttribute("username",username); return "redirect:/itemList.action"; }
拦截器方法1:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
if(!requestURI.equals("/Demo32/login.action")){
//表示如果不是访问登录页面的请求,那么就要判断他有没有登录
String username = (String) request.getSession().getAttribute("username");
if(username == null){
//表示如果没有登录,将其拦截并打回登录页面
response.sendRedirect(request.getContextPath()+"/login.action");
return false;
}
}
//以上条件都符合后会返回true,放行
return true;
}
🍓分页
分页两个比较重要的类,其中一个是PageHelper
,另外一个是PageInfo
-
导入分页包
<!-- https://mvnrepository.com/artifact/com.github.miemiedev/mybatis-paginator --> <dependency> <groupId>com.github.miemiedev</groupId> <artifactId>mybatis-paginator</artifactId> <version>1.2.15</version> </dependency> <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency>
-
配置
application-context.xml
配置文件<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="mapperLocations" value="classpath*:com/hospital/dao/*.xml"></property> <property name="configLocation" value="classpath:mybatis-cfg.xml"></property> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <value> <!--支持的数据库类型--> helperDialect=mysql reasonable=true </value> </property> </bean> </array> </property> </bean>
-
dao
层service
层编写(略) -
分析
PageInfo
类的属性//当前页 private int pageNum; //每页显示的记录数 private int pageSize; //当前页面的记录数 private int size; //起始页 private int startRow; //尾页 private int endRow; //总记录数 private long total; //总页数 private int pages; //结果集 private List<T> list; //前一页 private int prePage; //下一页 private int nextPage; //是否为第一页 private boolean isFirstPage; //是否为最后一页 private boolean isLastPage; //是否有前一页 private boolean hasPreviousPage; //是否有下一页 private boolean hasNextPage; //导航页码数 private int navigatePages; //所有导航页号 private int[] navigatepageNums; //导航起始页 private int navigateFirstPage; //导航最后一页 private int navigateLastPage;
-
前端(参考)
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <table> <thead> <tr> <th>医生编号</th> <th>医生姓名</th> <th>入院时间</th> <th>所属科室</th> <th>操作</th> </tr> </thead> <!--doctorList的类型为PageInfo类型--> <c:forEach items="${doctorList.list }" var="d" varStatus="status"> <tr> <td style="vertical-align: middle;"><input type="checkbox" name="check" value="1"></td> <td>${d.id }</td> <td>${d.name }</td> <td><fmt:formatDate value="${d.time }" pattern="yyyy年MM月dd日"/> </td> <td>${d.seccoXuan.seccoName }</td> <td><a href="doctor/toEditPage?id=${d.id }&pageNum=${doctorList.pageNum}">更改</a> <a href="doctor/detail?id=${d.id }&pageNum=${doctorList.pageNum}" >详情</a></td> </tr> </c:forEach> </table> <table> <tr> <th colspan="5"> <div class="inline pull-right page"> 共${doctorList.total }条记录 ${doctorList.pageNum }/${doctorList.pages } 页 <c:if test="${doctorList.isFirstPage }"> <a href="javascript:void()" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </c:if> <!--如果不是首页就可以往前跳一页--> <c:if test="${!doctorList.isFirstPage }"> <a href='${pageContext.request.contextPath}/doctor/forward.action?pageNum=${doctorList.pageNum - 1 }'>«</a> </c:if> <c:forEach items="${doctorList.navigatepageNums }" var="n"> <!-- 判断是否是当前页,是导航页就是选中状态 --> <c:if test="${n==doctorList.pageNum }"> <a class="product-ym_bg" href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${n }">${n }</a> </c:if> <!-- 判断是否是当前页,是导航页就是非选中状态 --> <c:if test="${n!=doctorList.pageNum}"> <a class="product-ym_bg" href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${n }">${n }</a> </c:if> </c:forEach> <!--如果是尾页--> <c:if test="${doctorList.isLastPage }"> <a href="javascript:void()" aria-label="Next"> <span aria-hidden="true">»</span> </a> </c:if> <!-- 如果不是最后一页,是就可以点击下一页 --> <c:if test="${!doctorList.isLastPage }"> <a class="product-ym_xyy" href="${pageContext.request.contextPath}/doctor/forward.action?pageNum=${doctorList.pageNum + 1 }" aria-label="Next"> <span aria-hidden="true">»</span> </a> </c:if> </div> <div> <button type="button" class="btn btn-success" onclick="addDoctor()">添加医生</button> <button type="button" class="btn btn-success" id="delPro" onClick="delAll();">删除选中</button> </div> </th> </tr> </table>
-
后端
@RequestMapping(value = "/forward.action",method = RequestMethod.GET,produces="text/html;charset=UTF-8") public String forward(Model model, @RequestParam(defaultValue = "1")int pageNum,@RequestParam(defaultValue = "2")int pageSize){ PageHelper.startPage(pageNum,pageSize);//该语句后面紧挨着的查询语句就会分页 List<Doctor> doctors = doctorService.find(); PageInfo<Doctor> doctorList = new PageInfo<Doctor>(doctors); model.addAttribute("doctorList",doctorList); return "/doctor/index"; }
🍓Spring请求转发(forward)和重定向(redirect)
//请求转发
return "forward:/itemEdit.action";
//重定向
return "redirect:/itemEdit.action?id="+item.getId();
区别:
- 地址显示不同,重定向显示跳转后的页面的地址,请求转发显示的是请求页面的地址(原来的地址)
- 请求转发客户端请求次数只有一次,因为是服务器内部帮客户端执行了后续的转发到第二个接口的工作,重定向请求次数是两次,客户端第一次请求后,接口会引导客户端去第二次请求另外一个接口(所以这也是为什么请求转发地址不变,重定向地址改变,并且不能共享请求参数,需要执行两次,且可以跳转到本项目以外的地址的原因)
- 请求转发只能跳转到自己项目的资源路径,重定向可以跳转到任意路径,不是自己的工程也可以跳
- 请求转发效率高,因为只执行一次请求,重定向效率低,执行两次请求
- 请求转发可以使用上一次的
request
对象,重定向后续的请求,没法使用上一次的request
存储的数据,或者没法使用上一次的request
对象,因为这是两次不同的请求
注意:
请求转发虽然效率高,但是存在风险,因为客户端地址不变,刷新会造成接口的重复请求,例如写操作,删除操作,修改操作最好使用重定向到列表
🍓拓展(JDBCTemplate)
在一些公司还会使用Spring
自带的JDBCTemplate
代替mybatis
,这里我引用一篇较好的博客来理解JDBCTemplate
的用法
JDBCTemplate的用法