SpringMVC
一、
springMVC作用在表现层,对请求参数进行处理,最会返回给浏览器响应结果,它通过一套注解让一个简单的java类成为处理请求的控制器, 而无需实现任何接口。同时支持RESTfull编程风格的请求。
M:model 模型 javabean
V:view 视图 jsp
C:controller 控制器 Servlet
springmvc与struts2区别
共同点:
它们都是表现层框架,都是基于 MVC 模型编写的。
它们的底层都离不开原始 ServletAPI。
它们处理请求的机制都是一个核心控制器。
区别:
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter
Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所
以 Spring MVC 会稍微比 Struts2 快些。(mvc是单例,s2是多例多了创建对象的时间所以慢)
Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便
(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注
解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)
Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提
升,尤其是 struts2 的表单标签,远没有 html 执行效率高。
开启springmvc的环境搭建:
1.导入依赖
2.在web.xml中写servlet映射
3.在resources中写springmvc.xml
4.配置服务器
代码:
1.在控制类上写@Controller注解
2.在springmvc.xml中写扫描注解标签
<context:component-scan base-package="cn.itcast"></context:component-scan>
3.在需要执行的方法上写@RequestMapping注解【这个对应的也需要在springmvc.xml中】
4.需要在web.xml中给servlet添加一个初始化参数把springmvc配置加载进去
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
5.在执行的方法里面写return返回值(这个返回值就是对应的要跳转到的jsp页面的名称)
6.用视图解析器才能完成跳转,需要在springmvc.xml中配置
<!--视图解析器对象-->
<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>
@RequestMapping注解
1. RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系
2. RequestMapping注解可以作用在方法和类上
1. 作用在类上:第一级的访问目录
2. 作用在方法上:第二级的访问目录
3. 细节:路径可以不编写 / 表示应用的根目录开始
4. 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /
3. RequestMapping的属性
1. path 指定请求路径的url
2. value value属性和path属性是一样的
3. mthod 指定该方法的请求方式 method={RequestMethod.POST}
4. params 指定限制请求参数的条件 params={"username"}代表要请求这个方法就必须带一个username的参数或 username=heihei.
5. headers 发送的请求中必须包含的请求头
请求参数的绑定
1. 请求参数的绑定说明
1. 绑定机制
1. 表单提交的数据都是k=v格式的 username=haha&password=123
2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的
3. 要求:提交表单的name和参数的名称是相同的
2. 支持的数据类型
1. 基本数据类型和字符串类型
2. 实体类型(JavaBean)
3. 集合数据类型(List、map集合等)
2. 基本数据类型和字符串类型
1. 提交表单的name和参数的名称是相同的
2. 区分大小写
3. 实体类型(JavaBean的封装)
1. 提交表单的name和JavaBean中的属性名称需要一致
2. 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name
4. 给集合属性数据封装(集合封装)
1. JSP页面编写方式:list[0].uname属性
2. map['one'].uname
5. 请求参数中文乱码的解决(解决从客户端传来中文字符时封装中文乱码)
1. 在web.xml中配置Spring提供的过滤器类
<!-- 配置过滤器,解决中文乱码的问题 -->
<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>
6. 自定义类型转换器
1. 表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行 型转换。
2. 如果想自定义数据类型转换,可以实现Converter的接口(比如日期类等等格式不符合规定)
1. 自定义类型转换器
public class StringToDateConverter implements Converter<String, Date>{
public Date convert(String source) {
if(source == null) {
throw new RuntimeException("参数不能为空");
}
try {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); // 解析字符串
Date date = df.parse(source);
return date;
} catch (Exception e) {
throw new RuntimeException("类型转换错误");
}
}
}
2. 注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 注册自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!-- 开启Spring对MVC注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>
7. 在控制器中使用原生的ServletAPI对象
1. 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象
常用的注解
1. RequestParam注解(解决浏览器提交属性名与形参不对应的问题)
1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值,
2. 属性
1. value:请求参数中的名称
2. required:请求参数中是否必须提供此参数,默认值是true,必须提供
3. 代码如下
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam(name = "name") String username){
System.out.println("执行了....");
System.out.println(username);
return "success";
}
2. RequestBody注解
1. 作用:用于获取请求体的内容(注意:get方法不可以,所以传表单)可以将返回数据转为json格式
2. 属性
1. required:是否必须有请求体,默认值是true
3. 代码如下
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了....");
System.out.println(body);
return "success";
}
3. PathVariable注解
1. 作用:拥有绑定url中的占位符的值。例如:url中有/delete/{id},{id}就是占位符
2. 属性
1. value:指定url中的占位符名称
3. Restful风格的URL
1. 请求路径一样可以根据不同的请求方式去执行后台的不同方法(规定不同的请求方式get post去找对应接收的getpost方法)
2. restful风格的URL优点
1. 结构清晰
2. 符合标准
3. 易于理解
4. 扩展方便
4. 代码如下
@RequestMapping("/testPathVariable/{sid}")
public String testPathVariable(@PathVariable(name = "sid") String id){
System.out.println("执行了....");
System.out.println(id);
return "success";
}
4. RequestHeader注解
1. 作用:获取指定请求头的值
2. 属性
1. value:请求头的名称
3. 代码如下
@RequestMapping(path="/hello")
public String sayHello(@RequestHeader(value="Accept") String header) {
System.out.println(header);
return "success";
}
5. CookieValue注解
1. 作用:用于获取指定cookie的名称的值
2. 属性
1. value:cookie的名称
3. 代码
@RequestMapping(path="/hello")
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) { System.out.println(cookieValue);
return "success";
}
6. ModelAttribute注解
1. 作用
1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。
2. 出现在参数上:获取指定的数据给参数赋值。
2. 应用场景
1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
3. 具体的代码
1. 修饰的方法有返回值
作用在方法,先执行
@ModelAttribute
public User showUser(String uname){
System.out.println("showUser执行了");
//通过用户查询数据库(模拟)
User user = new User();
user.setUname(uname);
user.setAge(20);
user.setDate(new Date());
return user;
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user){
System.out.println("testModelAttribute执行了....");
System.out.println(user);
return "success";
}
2. 修饰的方法没有返回值
作用在方法,先执行
@ModelAttribute
public void showUser(String name,Map<String, User> map) {
System.out.println("showUser执行了..."); // 模拟从数据库中查询对象
User user = new User();
user.setName("哈哈");
user.setPassword("123");
user.setMoney(100d);
map.put("abc", user);
}
修改用户的方法
@RequestMapping(path="/updateUser")
public String updateUser(@ModelAttribute(value="abc") User user) {
System.out.println(user);
return "success";
}
4. SessionAttributes注解
1. 作用:用于多次执行控制器方法间的参数共享
2. 属性
1. value:指定存入属性的名称
3. 代码如下
/**
* SessionAttributes的注解
* @return
*/
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes执行了....");
//底层hui存储到request域中
model.addAttribute("msg","meimei");
return "success";
}
/**
* 获取session中的值
* @param modelMap
* @return
*/
@RequestMapping("/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
System.out.println("getSessionAttributes执行了....");
//底层hui存储到request域中
String msg = (String)modelMap.get("msg");
System.out.println(msg);
return "success";
}
/**
* 删除session中的值
* @param status
* @return
*/
@RequestMapping("/delSessionAttributes")
public String delSessionAttributes(SessionStatus status){
System.out.println("delSessionAttributes执行了....");
status.setComplete();
return "success";
}
二、响应数据和结果视图
1. 返回值分类
1. 返回字符串
1. Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString执行了");
//模拟从数据库添加信息
User user = new User();
user.setUsername("马海龙");
user.setPassword("1234");
user.setAge(20);
//存起来
model.addAttribute("user",user);
return "success";
}
2. 返回值是void
1. 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
1. 默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
2. 可以使用请求转发或者重定向跳转到指定的页面
/**
* 返回值是Void的测试
* 请求转发试一次请求,不用去编写项目的名称
* 重定向:response.sendRedirect(request.getContextPath()+"/WEB-INF/pages/xxx.jsp")
*/
@RequestMapping("/testVoid")
public void testVoid(HttpServletResponse response, HttpServletRequest request) throws ServletException, IOException {
System.out.println("testVoid执行了");
//request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//重定向
//response.sendRedirect(request.getContextPath()+"/index.jsp");
//直接会进行响应
//设置中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print("你好");
}
3. 返回值是ModelAndView对象
1. ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
2. 具体的代码如下
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
System.out.println("testModelAndView执行");
ModelAndView mv = new ModelAndView();
//模拟从数据库添加信息
User user = new User();
user.setUsername("马海龙");
user.setPassword("1234");
user.setAge(20);
//把user对象存储到mv对象中,也会把user对象存入到request对象中
mv.addObject("user",user);
//跳转到哪个页面
mv.setViewName("success");
return mv;
}
2. SpringMVC框架提供的转发和重定向
1. forward请求转发
1. controller方法返回String类型,想进行请求转发也可以编写成
2. redirect重定向
1. controller方法返回String类型,想进行重定向也可以编写成
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect执行了");
//请求转发
//return "forward:/WEB-INF/pages/success.jsp";
//重定向
return "redirect:/index.jsp";
}
3. ResponseBody响应json数据
1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而
不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
1. mvc:resources标签配置不过滤
1. location元素表示webapp目录下的包下的所有文件
2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
2. 使用@RequestBody获取请求体数据
$(function(){ // 绑定点击事件
$("#btn").click(function(){
$.ajax({
url:"user/testJson",
contentType:"application/json;charset=UTF-8", data:'{"addressName":"aa","addressNum":100}',
dataType:"json", type:"post",
success:function(data){
alert(data);
alert(data.addressName);
}
});
});
});
@RequestMapping("/testJson")
public void testJson(@RequestBody String body) {
System.out.println(body);
}
3. 使用@RequestBody注解把json的字符串转换成JavaBean的对象
4. 使用@ResponseBody注解把JavaBean对象转换成json字符串,直接响应
5. json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
SpringMVC实现文件上传
1. 文件上传的回顾(web基础的)
1. 导入文件上传的jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
2. 编写文件上传的JSP页面
<form action="user/fileupload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
3. 编写文件上传的Controller控制器
@RequestMapping("/fileupload1")
public String fileupload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传");
//使用fileupload组件完成文件上传
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断,该路径是否存在
File file = new File(path);
if (!file.exists()){
//创建文件夹
file.mkdirs();
}
//解析request对象,获取上传的文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历
for (FileItem item:items) {
//进行判断,当前item对象是否是上传文件项
if (item.isFormField()){
//普通表单项
}else{
//说明是个上传文件项
//获取到上传文件名称
String filename = item.getName();
//完成上传文件
item.write(new File(path,filename));
//删除临时文件(大于10kb会有临时文件)
item.delete();
}
}
return "success";
}
2. SpringMVC传统方式文件上传
1. SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的
name属性名称相同。
2. 代码如下
@RequestMapping("/fileupload2")
public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("spring文件上传");
//使用fileupload组件完成文件上传
//上传位置
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断,该路径是否存在
File file = new File(path);
if (!file.exists()){
//创建文件夹
file.mkdirs();
}
//说明是个上传文件项
//获取到上传文件名称
String filename = upload.getOriginalFilename();
//把文件名设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "-" + filename;
//完成上传文件
upload.transferTo(new File(path,filename));
return "success";
}
3. 配置文件解析器对象
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
3. SpringMVC跨服务器方式文件上传
1. 搭建图片服务器
1. 根据文档配置tomcat9的服务器,现在是2个服务器
2. 导入资料中day02_springmvc5_02image项目,作为图片服务器使用
2. 实现SpringMVC跨服务器方式文件上传
1. 导入开发需要的jar包
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
2. 编写文件上传的JSP页面
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
3.编写控制器
@RequestMapping("/fileupload3")
public String fileupload3( MultipartFile upload) throws Exception {
System.out.println("spring跨服务器文件上传");
//定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";//图片服务器地址需要创建uploads文件夹
//说明是个上传文件项
//获取到上传文件名称
String filename = upload.getOriginalFilename();
//把文件名设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid + "-" + filename;
//完成上传文件
//创建客户端对象
Client client = Client.create();
//和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
//上传文件到服务器
webResource.put(upload.getBytes());
return "success";
}
SpringMVC的异常处理
1. 异常处理思路
1. Controller调用service,service调用dao,异常都是向上抛出的最终有,DispatcherServlet找异常处理器进行异常的处理
要配置异常处理器在xml文件中。
2. SpringMVC的异常处理
1. 编写自定义异常类(做提示信息的)
public class SysException extends Exception {
//存储提示信息的
private String message;
public SysException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2. 自定义异常处理器
public class SysExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
//获取到异常对象
SysException e = null;
if (ex instanceof SysException){
e = (SysException)ex;
}else{
e = new SysException("系统正在维护...");
}
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
3.配置异常处理器
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
SpringMVC框架中的拦截器
1.拦截器的概述
1. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。(Filter)
2. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链
中的拦截器会按着定义的顺序执行。
3. 拦截器和过滤器的功能比较类似,有区别
1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
2. 拦截器是SpringMVC框架独有的。
3. 过滤器配置了/*,可以拦截任何资源。
4. 拦截器只会对控制器中的方法进行拦截。(controller)
4. 拦截器也是AOP思想的一种实现方式
5. 想要自定义拦截器,需要实现HandlerInterceptor接口。
2. 自定义拦截器步骤
1. 创建类,实现HandlerInterceptor接口,重写需要的方法
public class MyInterceptor1 implements HandlerInterceptor {
/**
*预处理,controller方法执行之前执行
* return true放行,执行下一个拦截器,如果没有执行controller方法
* return false不放行,直接跳到某个页面
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了....前");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/*
* 后处理方法,controller方法执行后,success.jsp执行前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了....后");
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
*success.jsp页面执行后,该方法会执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了....最后");
}
}
2. 在springmvc.xml中配置拦截器类
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--你要拦截具体的方法-->
<mvc:mapping path="/user/*"/>
<!--你不拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean class="cn.itcast.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>