目录
SpringMVC概述
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合
是spring框架中的一个模块,是对servlet的封装,可以对请求中的数据封装处理,方便接收和响应
- springMVC 是 spring 框架的一个模块,springMVC 和 spring 无需通过中间整合层进行整合
- springmvc 是一个基于 mvc 的 web 框架,方便前后端数据的传输.
- Spring MVC 拥有控制器,接收外部请求,解析参数传给服务层
ssm
spring springMVC mybatis
mvc
早期的后期架构模式
Model
数据访问层:提供要展示的数据,因此包含数据和行为
Value Object(数据Dao) 和 服务层(行为Service)
提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务
- 业务逻辑
- 保存数据的状态
View
视图:负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西
- 显示页面
Controller
控制层:接收用户请求,委托给数据访问层进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作
- 取得表单数据
- 调用业务逻辑
- 响应
SpringMVC运行流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler
- 处理器映射器根据请求url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet
- DispatcherServlet 调用 HandlerAdapter处理器适配器,请求执行Handler
- HandlerAdapter 经过适配调用 具体处理器进行处理业务逻辑
- Handler执行完成返回 json字符串
注解原理
注解本质是一个继承了Annotation的特殊接口,其具体实现类是JDK动态代理生成的代理类。我们通过反射获取注解时,返回的也是Java运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,会最终调用AnnotationInvocationHandler的invoke方法,该方法会从memberValues这个Map中查询出对应的值,而memberValues的来源是Java常量池
结构
springMVC搭建
package com.ff.ssm.common;
/**
* 结果封装类
*
* @author Deevan
*/
public class CommonResult<T> {
private Integer code;
private String msg;
private T data;
public CommonResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
package com.ff.ssm.controller;
import com.ff.ssm.common.CommonResult;
import com.ff.ssm.model.Admin;
import com.ff.ssm.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping(path = "/login")
public class LoginController {
@Autowired
LoginService loginService;
/*
向ajax响应数据
springMVC添加@ResponseBody,会将return的数据直接转为json
*/
@ResponseBody
@PostMapping(path = "checkLogin")
public CommonResult<Admin> checkLogin(Admin admin){
CommonResult<Admin> commonResult = null;
try {
Admin adminBack = loginService.loginCheck(admin);
commonResult = new CommonResult<>(200,"登录成功",adminBack);
}catch (Exception e){
commonResult = new CommonResult<>(500,"登录失败",null);
e.printStackTrace();
}
return commonResult;
}
}
package com.ff.ssm.dao;
import com.ff.ssm.model.Admin;
public interface LoginDao {
Admin LoginCheck(Admin admin);
}
package com.ff.ssm.service;
import com.ff.ssm.dao.LoginDao;
import com.ff.ssm.model.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class LoginService {
@Autowired
LoginDao loginDao;
public Admin loginCheck(Admin admin){
return loginDao.LoginCheck(admin);
}
}
loginMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace="某个接口的名称"-->
<mapper namespace="com.ff.ssm.dao.LoginDao">
<select id="LoginCheck" parameterType="Admin" resultType="Admin">
select * from admin where account=#{account} and password=#{password}
</select>
</mapper>
db.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 导入属性文件 -->
<context:property-placeholder location="classpath:config.properties"/>
<!-- 创建阿里德鲁伊数据库连接管理对象 -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${uname}"/>
<property name="password" value="${pwd}"/>
<property name="initialSize" value="${initialSize}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxActive" value="${maxActive}"/>
</bean>
<!-- 配置spring事务管理类,并注入数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="druidDataSource"/>
</bean>
<!-- 开启spring事务管理注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
mybatis-config.xml
<?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">
<!--mybatis核心配置文件-->
<configuration>
<settings>
<setting name="logImpl" value="LOG4J"/>
<!--开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--懒加载-->
<!--<setting name="lazyLoadingEnabled" value="true"/>-->
<setting name="lazyLoadTriggerMethods" value=""/>
<!--全局开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.ff.ssm.model"/>
</typeAliases>
</configuration>
spring,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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://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
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启spring注解扫描 -->
<context:component-scan base-package="com.ff.ssm"> </context:component-scan>
<!-- 与数据库连接相关 -->
<import resource="db.xml"/>
<!-- 与mybatis相关 -->
<import resource="spring-mybatis.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
spring-mvc.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:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启spring-mvc全局注解扫描 -->
<mvc:annotation-driven/>
<!--当 DispatcherServlet 的 url 配置为/时 需要添加此配置,能够访问静态资源 例如.jpg,.js,.css 带有后缀名文件-->
<mvc:default-servlet-handler/>
</beans>
spring-mybatis.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- spring管理生成sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--扫描所有的Mapper.xml文件-->
<property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/>
</bean>
<!-- 生成指定包下面的接口代理对象 -->
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--扫描dao下所有的接口-->
<property name="basePackage" value="com.ff.ssm.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
</beans>
web.xml
在tomcat启动时读取创建DispatcherServlet对象,并加载spring.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">
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 找web-inf/classes/配置文件 -->
<param-value>classpath:spring.xml</param-value>
</init-param>
<!-- 服务器启动时创建servlet -->
<load-on-startup>0</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>
控制器类搭建
@Controller 用于标记在一个类上,使用它标记的类就是一个 SpringMVC Controller 对象.
Spring 配置中指定了自动扫描的 basepackage 后,Spring 会扫描这些包以及子包中的使用了@Controller 标识的类,然后将类加入到 Spring IOC 容器中,注入依赖。
Ajax请求多用**@RestController**:返回值自动转为为json形式
接收请求
@RequestMapping 注解是一个用来处理请求地址映射的注解,可用于类或方法上。
path / value和method 底层可以传string[ ] : 都可以为多个
method:get / post都可以接收
获取请求数据
接收变量
如果请求中的键与接收的变量同名,可省略@RequestParam(" ")
接收对象
HandlerAdapter 会将这个对象的实例创建出来,然后从请求参数中取出这些参数然后放到实体对象中,需要注意的是请求参数的名字需要与实体类中的属性一一对应,只有对应的属性才会提取参数的值
日期类型
要在接收参数的日期上添加了一个@DateTimeFormat,要指定 Date 类型的格式,就可以把接收到的请求中的数据转换成Date类型
过滤静态资源文件
当 DispatcherServlet 的 url 配置为/时 需要添加此配置,能够访问静态资源例如.jpg,.js,.css 带有后缀名文件。
在 springMVC-servlet.xml 中配置<mvc:default-servlet-handler />后,
会在 Spring MVC 上下文中定义一个 org.springframework.web.servlet.resource.DefaultServletHttpRequest Handler,它会像一个检查员,对进入 DispatcherServlet 的 URL 进行筛查,
如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
Ajax返回JSON
@responseBody 注解的作用是将 controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到 response 对象的 body 区,通常用来向异步请求返回 JSON 数据。
注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过 response 对象输出指定格式的数据。
前提添加转json的jar包
如果整个类都是用json格式响应,可以在类上定义为 @RestController
中文乱码处理
我们发现在提交请求的时候,如果输入的是中文,处理器方法获取到之后是 乱码。解决的方法就是添加 一个过滤器,为 request 对象设置编码集。SpringMVC 中已经为我们提供了这 个过滤器,只需要在 web.xml 中配置好即可
<!-- 编码过滤器 -->
<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>
文件上传与显示
搭建
1、导入jar包
<!--文件上传下载-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2、在spring-mvc.xml 中配置文件解析器
<!-- 文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10485760"/>
</bean>
3、在tomcat配置中加入文件包地址
4、 在html 中导入 ajaxfileupload.js
流程
1、在服务器端创建一个文件夹来保存用户的文件userImg
2、用户上传文件
3、我们要把用户上传的头像文件放在以其账号名称为命名的子文件夹中
4、在数据库中保存该文件的名称(为防止重名,生成一个新文件名)
5、在回调中为用户返回该文件名
6、把userImg文件夹、用户账号名、文件名拼接成的路径在服务器中查找显示该头像文件
7、同样在登录成功后success页面拿到该路径并显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-1.8.3.js" type="text/javascript" charset="utf-8"></script>
<script src="js/ajaxfileupload.js"></script>
<script type="text/javascript">
function upLoad() {
//发送ajaxFileUpload请求
$.ajaxFileUpload({
url: 'file/upload', //接收地址
fileElementId: 'fileID', //上传文件的input的id
dataType: 'json', //接收数据类型为json
success: function (data) {
//判断后端用后session是否存在
if (data === 202) {
alert("登录失效,请重新登录")
location.replace("index.html")
} else {
//拿到用户账号名
var account = window.sessionStorage.getItem("account")
var imgUrl = "http://127.0.0.1:8080/userImg/" + account + "/" + data.data.newFileName
window.parent.document.getElementById("pictureId").innerHTML = "<img src=" + imgUrl + " height='30' width='30'>"
}
}
}
)
}
</script>
</head>
<body>
<input type="file" name="fileName" id="fileID" accept=".jpg,.png">
<input type="button" value="上传" onclick="upLoad()">
</body>
</html>
package com.ff.ssm.controller;
@RestController
@RequestMapping(path = "/file")
public class FileController {
@Autowired
AdminService adminService;
@PostMapping(path = "/upload")
public CommonResult<Admin> fileUpload(@RequestParam("fileName") CommonsMultipartFile file, HttpSession session) {
CommonResult<Admin> commonResult = null;
Admin admin = (Admin) session.getAttribute("admin");
File f = new File("F:\\test\\ssm\\userImg\\" + admin.getAccount());
if (!f.exists()) {
f.mkdir();
}
//防止文件重名,生成保存其新文件名
String oldFileName = file.getOriginalFilename();
String newFileName = StringUtil.getNewFileName(oldFileName);
File f1 = new File(f, newFileName);
try {
//将文件输出到指定的目录
file.transferTo(f1);
//保存用户和文件关系
Admin admin1 = new Admin();
admin1.setId(admin.getId());
admin1.setOldFileName(oldFileName);
admin1.setNewFileName(newFileName);
adminService.addAdminFile(admin1);
commonResult = new CommonResult<>(200, "上传成功", admin1);
} catch (IOException e) {
e.printStackTrace();
commonResult = new CommonResult<>(500, "上传失败", null);
}
return commonResult;
}
}
adminMapper:
<update id="addAdminFile" parameterType="Admin">
update admin
set new_file_name = #{newFileName},
old_file_name = #{oldFileName}
where id = #{id}
</update>
拦截器
拦截器位置
原servlet框架中过滤器位置:
请求-----服务器------过滤器-----servlet------service-----jdbc
springMVC中拦截器位置:
请求-----服务器-----DispatcherServlet-----HandlerMapping-----拦截器-----HandlerAdapter-----Handler-----service-----jdbc
拦截器实现
拦截器实现类:
package com.ff.ssm.util;
/**
* 后端session拦截器
*
* @author Deevan
*/
//继承HandlerInterceptor接口
public class LoginInterceptor implements HandlerInterceptor {
//预处理:进入控制器前被执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
Admin admin = (Admin) session.getAttribute("admin");
if (admin == null) {
response.getWriter().print(202);
//流程中断,不会继续调用其他的拦截器或处理器方法,此时我们需要通过 response 来产生响应
return false;
} else {
//继续流程
return true;
}
}
//后处理方法:就是在处理器方法调用完成,但在渲染 视图之前,该方法被调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
//整个请求处理完毕,即在视图渲染完毕时该方法被执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
配置拦截器:
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置进入拦截器的页面 -->
<mvc:mapping path="/**"/>
<!-- 配置不进入的页面 -->
<mvc:exclude-mapping path="/login/checkLogin"/>
<mvc:exclude-mapping path="/css/**"/>
<mvc:exclude-mapping path="/js/**"/>
<mvc:exclude-mapping path="/images/**"/>
<mvc:exclude-mapping path="/**.html"/>
<!-- 实现类 -->
<bean class="com.ff.ssm.util.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
文件数据同步保存
文件数据同步上传
1、ajaxFileUpload()中加入data上传数据
function save() {
if (confirm("确认保存")){
var title = $("#title").val()
var newsTypeId = $("#newsTypeId").val()
var summary = $("#summary").val()
var content = editor.getData();
$.ajaxFileUpload({
url: '../../news/addNews',
fileElementId: 'coverPicture',
dataType: 'json',
data: {
title: title,
newsId: newsTypeId,
summary: summary,
content: content
},
success: function (res) {
if (res.code===500){
alert(res.msg)
}else if (res.code===202){
alert("登录失效")
}else {
alert(res.msg)
location.replace("list.html")
}
}
})
}
}
文件sql异步
2、加入图片改变事件,上传图片,返回图片的地址,隐藏在前端页面,还可以在前端显示图片,随后点击保存时,才发出添加SQL
//将文件上传到服务器user/userId/newFileName,但是不改变数据库文件,而是返回该文件的新文件名,将文件名隐藏到表单中
function setUserFile() {
$.ajaxFileUpload({
url: '../../user/setUserFile',
fileElementId: 'fileID',
dataType: 'json',
success: function (res) {
if (res.code === 500) {
alert("服务器忙,请稍后再试")
} else {
//显示
var imgUrl = "http://127.0.0.1:8080/tomorrowNewsFiles/user/" + userId + "/" + res.data
document.getElementById("img").innerHTML = "<img src=" + imgUrl + " height='100' width='100'>"
//隐藏到表单
$("#imgUrl").val(res.data)
alert(res.msg);
}
}
}
)
}