SpringMVC学习文档
springMVC就是类似与Struts2的mvc框架,始于SpringFrameWork的后续产品
为什么要学习SpringMVC?
springMVC 与 Struts2 区别 对比项目 SpringMVC Struts2 优势 国内市场情况 有大量用户,一般新项目启动都选择springmvc 有部分老用户,一直在使用 国内情况springmvc的shiyonglv已经超过了struts2 框架入口 基于servlet 基于filter 只是配置方式不同 框架设计思想 控制器基于方法级别的拦截,处理器设计为单实例 控制器基于类级别拦截,处理器设计为多实例 由于设计本身的原因,造成了struts2只能设计为多实例模式,相比于springmvc设计为单实例模式,struts2会消耗更多服务器内存 参数传递 通过方法入参传递 通过类的成员变量传递 struts2通过成员变量传递参数,导致参数线程不安全,有可能引发并发的问题 与spring整合 与spring同一家公司可以与spring无缝整合 需要整合包 springmvc与spring整合更轻松
一.概述
1.1SpringMVC入门
1.1.1配置核心控制器web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 配置spring mvc的核心控制器-->
<servlet>
<servlet-name>SpringMVCDispatcherServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 配置初始化参数,用于读取SpringMVC的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC.xml</param-value>
</init-param>
<!-- 配置servlet的对象的创建时间点:应用加载时创建。
取值只能是非0正整数,表示启动顺序-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVCDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
1.1.2配置springmvc配置文件springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置创建spring容器要扫描的包-->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 配置视图解析器-->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--开启springmvc框架注解的支持 -->
<mvc:annotation-friven/>
</beans>
1.1.3编写控制器并使用注解配置
@Controller("helloController")
public class HelloController {
@RequestMapping("/hello")
public String sayHello() {
System.out.println("HelloController的sayHello 方法执行了。。。。");
return "success";
}
}
1.2SpringMVC架构
1.2.1框架默认加载组件
处理器映射器与处理器适配器
处理器映射器
从spring3.1开始,废除了DefaultAnnotationHandlerMapping的使用,推荐使用RequestMappingHandlerMapping完成注解式处理器映射
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> 处理器适配器
从spring3.1开始,废除了AnnotationMethodHandlerMapping的使用,推荐使用RequestMappingHandlerAdapter完成注解式处理器适配
<bean class"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter "/>
<! --配置注解驱动相当于同时使用最新的处理器映射器和处理器适配器 ,对json数据响应提供支持 -->
<mvc:annotation-driven />
视图解析器
mav.setViewName("itemList");
在springmvc.xml中
1.3概述
Spring web MVC框架提供了MVC(模型 - 视图 - 控制器)架构和用于开发灵活和松散耦合的Web应用程序的组件。 MVC模式导致应用程序的不同方面(输入逻辑,业务逻辑和UI逻辑)分离,同时提供这些元素之间的松散耦合。
- 模型(Model)封装了应用程序数据,通常它们将由
POJO
类组成。 - 视图(View)负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出。
- 控制器(Controller)负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染。
1.4优点
1、清晰的角色划分:
前端控制器(DispatcherServlet)
请求到处理器映射(HandlerMapping)
处理器适配器(HandlerAdapter)
视图解析器(ViewResolver)
处理器或页面控制器(Controller)
验证器(Validator)
命令对象(Command 请求参数绑定到的对象就叫命令对象)
表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。
2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。
3、由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象。
4、和Spring 其他框架无缝集成,是其它Web框架所不具备的。
5、可适配,通过HandlerAdapter可以支持任意的类作为处理器。
6、可定制性,HandlerMapping、ViewResolver等能够非常简单的定制。
7、功能强大的数据验证、格式化、绑定机制。
8、利用Spring提供的Mock对象能够非常简单的进行Web层单元测试。
9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。
10、强大的JSP标签库,使JSP编写更容易。
………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配
置支持等等。
1.5.RequestMapping注解
1.5.1作用
用于建立请求URL和处理请求方法之间的对应关系。
出现的位置
类上:请求URL一级目录
方法上:请求URL二级目录
1.5.2属性
value:用于指定请求的URL 与path属性相同(若只有value属性 value可省略)
method:用于指定请求的方式
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和
配置的一模一样。
例如:
params = {"accountName"},表示请求参数必须有accountName
params = {"moeny!100"},表示请求参数中money不能是100。
headers:用于指定限制请求消息头的条件。
二.请求参数的绑定
2.1绑定机制
我们都知道,表单中请求参数都是基于key=value的。
SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。
例如:
< a href="account/findAccount?accountId=10">查询账户中请求参数是:
accountId=10@RequestMapping("/findAccount")
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success";
2.2支持数据类型
基本类型参数:
包括基本类型和String类型
POJO类型参数:
包括实体类,以及关联的实体类
数组和集合类型参数:
包括List结构和Map结构的集合(包括数组)
Model类型:
用于数据的返回详见4.1.1
SpringMVC绑定请求参数是自动实现的,但是要想使用,必须遵循以下使用要求。
如果是基本类型或者String类型:
要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是POJO类型,或者它的关联对象:
要求表单中参数名称和POJO类的属性名称保持一致。并且控制器方法的参数类型是POJO类型。若是POJO含有包装对象则通过 . 来传递属性
如果是集合类型,有两种方式:
第一种:
要求集合类型的请求参数必须在POJO中。在表单中请求参数名称要和POJO中集合属性名称相同。
给List集合中的元素赋值,使用下标。
给Map集合中的元素赋值,使用键值对。
public class User implements Serializable {
private String username;
private String password;
private Integer age;
private List<Account> accounts;
private Map<String,Account> accountMap;
<form action="account/updateAccount" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
账户1名称:<input type="text" name="accounts[0].name" ><br/>
账户1金额:<input type="text" name="accounts[0].money" ><br/>
账户2名称:<input type="text" name="accounts[1].name" ><br/>
账户2金额:<input type="text" name="accounts[1].money" ><br/>
账户3名称:<input type="text" name="accountMap['one'].name" ><br/>
账户3金额:<input type="text" name="accountMap['one'].money" ><br/>
账户4名称:<input type="text" name="accountMap['two'].name" ><br/>
账户4金额:<input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value="保存">
</form>
第二种:
接收的请求参数是json格式数据。需要借助一个注解实现。
2.3请求参数乱码
在web.xml中配置过滤器
<!-- 配置springMVC编码过滤器-->
<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-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在springmvc的配置文件中可以配置,静态资源不过滤:
<!-- location表示路径,mapping表示文件,**表示该目录下的文件以及子目录的文件-->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/scripts/" mapping="/javascript/**"/>
2.4自定义类型转换器
Springmvc在提交请求时所有的参数都是String类型 ,只不过springmvc在封装的时候会对大部分基本数据类型进行数据类型转换。
但使用date时提交2020/01/01 会帮助转换,但提交2020-01-01时springmvc不支持这种格式的日期转换所以需要自定义类型转换器
第一步:定义一个类,实现Converter接口,该接口有两个泛型。
public class StringToDateConverter implements Converter<String, Date> {
/**
* 用于把String类型转成日期类型
*/
@Override
public Date convert(String source) {
DateFormat format = null;
try {
if(StringUtils.isEmpty(source)) {
throw new NullPointerException("请输入要转换的日期");
}
format = new SimpleDateFormat("yyyy-MM-dd");
Date date = format.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("输入日期有误");
}
}
}
第二步:在spring配置文件中配置类型转换器。
<!-- 配置类型转换器工厂-->
<bean id="converterService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器-->
<property name="converters">
<array>
<!-- 配置自定义类型转换器-->
<bean class="com.itheima.web.converter.StringToDateConverter"></bean>
</array>
</property>
</bean>
第三步:在annotation-driven标签中引用配置的类型转换服务
<mvc:annotation-driven
conversion-service="converterService"></mvc:annotation-driven>
三.常用注解
3.1RequestParam
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
示例:
<!-- requestParams注解的使用-->
<a href="springmvc/useRequestParam?name=test">requestParam注解</a>
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name")String username,
@RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
3.2RequestBody
作用:
用于获取请求体内容。直接使用得到是key=value&key=value...结构的数据。
get请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。当取值为true时,get请求方式会报错。如果取值
为false,get请求得到是null。
示例
post请求jsp代码:
<!-- request body注解-->
<form action="springmvc/useRequestBody" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
get请求jsp代码:
<a href="springmvc/useRequestBody?body=test">requestBody注解get请求</a>
控制器代码:
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return "success";
}
结果:post打印数据get打印null
3.3PathVaribale
作用:
用于绑定url中的占位符。例如:请求url中/delete/{id},这个{id}就是url占位符。
url支持占位符是spring3.0之后加入的。是springmvc支持rest风格URL的一个重要标志。
属性:
value:用于指定url中占位符名称。
required:是否必须提供占位符。
示例
<!-- PathVariable注解-->
<a href="springmvc/usePathVariable/100">pathVariable注解</a>
@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "success";
}
3.4CookieValue
作用:
用于把指定cookie名称的值传入控制器方法参数。
属性:
value:指定cookie的名称。
required:是否必须有此cookie。
3.5ModelAttribute
作用:
该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可
以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的key。key可以是POJO的属性名称,也可以是map结构的key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
例如:
我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数
据是肯定没有此字段的内容,一旦更新会把该字段内容置为null,此时就可以使用此注解解决问题。
四.响应数据和结果试图
4.1返回值分类
4.1.1字符串
controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
//指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/pages/success.jsp
@RequestMapping("/testReturnString")
public String testReturnString(Model model) {
System.out.println("AccountController的testReturnString 方法执行了。。。。");
User user =new User();
model.addAttribute("user",user);
return "success";
}
success.jsp
<html>
....
<body>
${user.name} //如此即可取值
</body>
</html>
4.2.2void
如果没有return 会自动跳到此路径的jsp 比如 testReturnVoid.jsp
@RequestMapping("/testReturnVoid")
public void testReturnVoid(HttpServletRequest request,HttpServletResponse response)
throws Exception {
}
//此时若想跳转
//1:使用request转发
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,
response);
//2:使用response页面重定向
response.sendRedirect("testRetrunString");
//3:使用response指定响应结果
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
4.2.3ModelAndView
ModelAndView是SpringMVC为我们提供的一个对象,该对象也可以用作控制器方法的返回值。总体上与4.1.1中的类似。
该对象有两个方法:
addObject() 添加模型到对象中 与model类似 在jsp中用el表达式即可获取 ${attributeName}
setViewName() 用于设置逻辑视图名称
示例
@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
ModelAndView mv = new ModelAndView();
mv.addObject("username", "张三");
mv.setViewName("success");
return mv;
}
我们在页面上上获取使用的是requestScope.username取的,所以返回ModelAndView类型时,浏
览器跳转只能是请求转发。
4.2转发和重定向
4.3ResponseBody 响应json数据
作用:
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定格式的
数据如:json,xml等,通过Response响应给客户端
jsp中的代码:
<script type="text/javascript"
src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$("#testJson").click(function(){
$.ajax({
type:"post",
url:"${pageContext.request.contextPath}/testResponseJson",
contentType:"application/json;charset=utf-8",
data:'{"id":1,"name":"test","money":999.0}',
dataType:"json",
success:function(data){
alert(data);
}
});
});
})
</script>
<!-- 测试异步请求-->
<input type="button" value="测试ajax请求json和响应json" id="testJson"/>
控制器中的代码:
/**
* 响应json数据的控制器
* @author 黑马程序员
* @Company
* @Version 1.0
*/
@Controller("jsonController")
public class JsonController {
/**
* 测试响应json数据
*/
@RequestMapping("/testResponseJson")
public @ResponseBody Account testResponseJson(@RequestBody Account account) {
System.out.println("异步请求:"+account);
return account;
}
}
五.SpringMVC实现文件上传
5.1原理分析
5.1.1前提
A form表单的enctype取值必须是:multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型
B method属性取值必须是Post
C 提供一个文件选择域< input type="file" />
一定要确保在您的 classpath 中有最新版本的 commons-fileupload.x.x.jar 文件。
一定要确保在您的 classpath 中有最新版本的 commons-io-x.x.jar 文件。
5.1.2示例
jsp代码
<form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data">
选择一个文件:
<input type="file" name="uploadFile" />
<br/><br/>
<input type="submit" value="上传" />
</form>
servlet代码
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
/**
* 上传数据及保存文件
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 检测是否为多媒体上传
if (!ServletFileUpload.isMultipartContent(request)) {
// 如果不是则停止
PrintWriter writer = response.getWriter();
writer.println("Error: 表单必须包含 enctype=multipart/form-data");
writer.flush();
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文处理
upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = getServletContext().getRealPath("/") + File.separator + UPLOAD_DIRECTORY;
// 如果目录不存在则创建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
try {
// 解析请求的内容提取文件数据
@SuppressWarnings("unchecked")
List<FileItem> formItems = upload.parseRequest(request);
if (formItems != null && formItems.size() > 0) {
// 迭代表单数据
for (FileItem item : formItems) {
// 处理不在表单中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// 在控制台输出文件的上传路径
System.out.println(filePath);
// 保存文件到硬盘
item.write(storeFile);
request.setAttribute("message",
"文件上传成功!");
}
}
}
} catch (Exception ex) {
request.setAttribute("message",
"错误信息: " + ex.getMessage());
}
}
}
5.2springmvc传统方式文件上传
传统方式的文件上传,指的是我们上传的文件和访问的应用存在于同一台服务器上。
并且上传完成之后,浏览器可能跳转。
步骤
-
拷贝5.1中的两个jar包
-
jsp页面
<form action="/fileUpload" method="post" enctype="multipart/form-data"> <imput type="file" name="uploadFile"/ > <input type="submit" value="上传"> </form>
-
编写控制器
@Controller("fileUploadController") public class FileUploadController { /** * 文件上传 */ @RequestMapping("/fileUpload") public String testResponseJson(String picname,MultipartFile uploadFile,HttpServletRequest request) throws Exception{ //定义文件名 String fileName = ""; //1.获取原始文件名 String uploadFileName = uploadFile.getOriginalFilename(); //2.截取文件扩展名 String extendName uploadFileName.substring(uploadFileName.lastIndexOf(".")+1, uploadFileName.length()); //3.把文件加上随机数,防止文件重复 String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); //4.判断是否输入了文件名 if(!StringUtils.isEmpty(picname)) { fileName = uuid+"_"+picname+"."+extendName; }else { fileName = uuid+"_"+uploadFileName; } System.out.println(fileName); //2.获取文件路径 ServletContext context = request.getServletContext(); String basePath = context.getRealPath("/uploads"); //3.解决同一文件夹中文件过多问题 String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); //4.判断路径是否存在 File file = new File(basePath+"/"+datePath); if(!file.exists()) { file.mkdirs(); } //5.使用MulitpartFile接口中方法,把上传的文件写到指定位置 uploadFile.transferTo(new File(file,fileName)); return "success"; } }
-
配置文件解析器
<!-- 配置文件上传解析器-->
<bean id="multipartResolver" <!-- id的值是固定的-->
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
注意:
文件上传的解析器id是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他
字段也将无法绑定)
5.3springmvc跨服务器上传
5.3.1分服务器目的
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
(注意:此处说的不是服务器集群)
分服务器目的是为了让服务器各司其职,提高运行效率
5.3.2步骤
准备两个服务器
在文件服务器的tomcat配置中加入允许读写操作
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param> //
<param-name>readonly</param-name> //加入这几行的目的是:
<param-value>false</param-value> //
</init-param> //接收文件的目标服务器可以支持写入操作
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
将上面两个jar包,以及jersey-client-1.18.1.jar、jersey-core-1.18.1.jar导入项目
编写控制器
@Controller("fileUploadController2")
public class FileUploadController2 {
public static final String FILESERVERURL =
"http://localhost:9090/day06_spring_image/uploads/";
/**
* 文件上传,保存文件到不同服务器
*/
@RequestMapping("/fileUpload2")
public String testResponseJson(String picname,MultipartFile uploadFile) throws Exception{
//定义文件名
String fileName = "";
//1.获取原始文件名
String uploadFileName = uploadFile.getOriginalFilename();
//2.截取文件扩展名
String extendName uploadFileName.substring(uploadFileName.lastIndexOf(".")+1,
uploadFileName.length());
//3.把文件加上随机数,防止文件重复
String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
//4.判断是否输入了文件名
if(!StringUtils.isEmpty(picname)) {
fileName = uuid+"_"+picname+"."+extendName;
}else {
fileName = uuid+"_"+uploadFileName;
}
System.out.println(fileName);
//5.创建sun公司提供的jersey包中的Client对象
Client client = Client.create();
//6.指定上传文件的地址,该地址是web路径
WebResource resource = client.resource(FILESERVERURL+fileName);
//7.实现上传
String result = resource.put(String.class,uploadFile.getBytes());
System.out.println(result);
return "success";
}
}
编写jsp
<form action="fileUpload2" method="post" enctype="multipart/form-data">
名称:<input type="text" name="picname"/><br/>
图片:<input type="file" name="uploadFile"/><br/>
<input type="submit" value="上传"/>
</form>
配置解析器
<!-- 配置文件上传解析器-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
六.SpringMVC中的拦截器
Spring MVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺
序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
过滤器是servlet规范中的一部分,任何java web工程都可以使用。
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦
截的。
它也是AOP思想的具体应用。
我们要想自定义拦截器,要求必须实现:HandlerInterceptor接口。
七.SSM整合
7.1环境准备
创建数据库和表结构
创建maven工程
导入坐标建立依赖
注意mybatis与spring对应关系
mybatis-spring | mybatis | spring |
---|---|---|
1.0.0 and1.0.1 | 3.0.1 to3.0.5 | 3.0.0 or higher |
1.0.2 | 3.0.6 | 3.0.0 or higher |
1.1.0 or higher | 3.1.0 or higher | 3.0.0 or higher |
1.3.0 or higher | 3.4.0 or higher | 3.0.0 or higher |
编写pojo
便也业务层和持久层接口
7.2整合步骤
7.2.1保证Spring在web工程中独立运行
编写spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop http://www.springframework.org/schema/aop/spring-aop-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/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置spring创建时要扫描的包 -->
<context:component-scan base-package="com.loserfromlazy">
<!--指定骚包规则,不扫描@Controller注解的java类-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller">
</context:exclude-filter>
</context:component-scan>
</beans>
使用注解配置业务层和持久层
@Service、@Repository
7.2.2保证SpringMVC在web工程中独立运行
在web.xml中配置核心控制类
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>boot-crm</display-name>
<!--配置spring mvc的编码过滤器-->
<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-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置spring mvc的核心控制器-->
<servlet>
<servlet-name>boot-crm</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置初始化参数,用于读取springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<!--配置servlet的对象的创建时间点:应用加载时创建。取值只能是非0正整数,表示启动顺序-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>boot-crm</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
编写springmvc配置文件
<?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:p="http://www.springframework.org/schema/p"
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-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置Controller扫描 -->
<context:component-scan base-package="com.yhr.crm.controller"/>
<!--另一种配置Controller的方式,使用时一种即可-->
<context:component-scan base-package="com.loserfromlazy">
<!--指定扫包规则,只扫描@Controller注解的java类-->
<context:ixclude-filter type="annotation" expression="org.springframework.stereotype.Controller">
</context:ixclude-filter>
</context:component-scan>
<!-- 配置注解驱动 -->
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
编写Controller和jsp
7.2.3整合spring和springmvc
配置监听器实现启动服务创建容器
在web.xml中加入
<!--配置spring提供的监听器,用于启动服务时加载容器
该监听器只能加载WEB-INF目录中名称为applicationContext.xml的配置文件-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--手动指定配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
7.2.4 保证Mybatis在web程序中独立运行
编写dao接口的映射文件
编写SqlMapConfig
<?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>
<!-- 加载属性文件 -->
<properties resource="log4j.properties">
<!--properties中还可以配置一些属性名和属性值 -->
<!-- <property name="jdbc.driver" value=""/> -->
</properties>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/pojo?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true" />
<property name="username" value="root" />
<property name="password" value="manager" />
</dataSource>
</environment>
</environments>
<!-- 加载 映射文件 -->
<mappers>
<mapper resource="mybatis/user.xml"/>
</mappers>
</configuration>
7.2.5 整合Mybatis和Spring
清空SqlMapConfig.xml内容,把其中内容配置到spring中
<?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>
</configuration>
PS:由于我们使用的是代理开发dao的方式,所以Dao的具体实现类由Mybatis使用代理方式创建,所以mybatis的配置文件不能删除。
当我们整合mybatis和spring时,mybatis创建的mapper.xml和dao接口文件名必须一致
使用spring接管mybatis的session工程
<!-- 配置 读取properties文件 jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis核心配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
配置自动扫描所有mapper接口和文件
<!-- 配置Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 设置Mapper扫描包 -->
<property name="basePackage" value="com.loserfromlazy.dao"/>
</bean>
配置事务
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="create*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 切面 -->
<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.lofromlazy.service.*.*(..))"/>
</aop:config>
applicationContext-dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop http://www.springframework.org/schema/aop/spring-aop-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/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置 读取properties文件 jdbc.properties -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置MyBatis核心配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 别名包扫描 -->
<property name="typeAliasesPackage" value="com.yhr.crm.pojo"/>
</bean>
<!-- 配置Mapper扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 设置Mapper扫描包 -->
<property name="basePackage" value="com.yhr.crm.mapper"/>
</bean>
</beans>