导航
一. 响应
1.1 概述:就是把后台的数据返回给浏览器/用户;
1.2 搭建环境:
- 创建项目:Maven->选择骨架或者手动添加… 在main中创建java,resources,webapp三个包,webapp包下创建WEB-INF,pages:创建succes.jsp;[成功的返回页面]
- 导入相关坐标… [可以应用版本锁定]
- 引入前端控制器[固定写法]
- springmvc.xml:开启注解扫描,视图解析器,注解支持
- 删除webapp中的index.jsp重新创建一个;
1.3. 响应数据和结果视图:
- Controller方法返回字符串 【使用Model存入数据再返回】
- 解析: Controller方法执行后,返回的字符串根据视图解析器所前后拼接的文件名和地址,就能成功的跳转到所需的页面;
- jsp页面接收对象:
- 在Controller方法中,使用model.addAttribute(“user”,user) [该方法需传入一个Model]
- Model不需要我们创建,这是框架为我们生成的;
- isELIgnored=“false” [识别el表达式]
- 使用${user.username}进行取值…
- 示例:
* @Controller
* @RequestMapping("/user")
* public class UserController {
* /**
* *请求参数的绑定
* */
* @RequestMapping(value="/initUpdate")
* public String initUpdate(Model model) {
* // 模拟从数据库中查询的数据
* User user = new User();
* user.setUsername("张三");
* user.setPassword("123");
* user.setMoney(100d);
* user.setBirthday(new Date());
* model.addAttribute("user", user);
* return "update";
* }
* }
-
Controller方法返回void 【return;】
- 请求转发:请求转发是一次请求,不能简写 [手动跳动转发,不会触动视图解析器,需要自己写全路径和文件格式]
示例:request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
- 重定向:请求转发是可以直接访问web-inf下的文件,所以不用写虚拟地址;
reponse.sendRedirect(request.getContextPath()+"WEB-INF/pages/xxx.jsp")
- 解决中文乱码:
reponse.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
- 直接响应:
response.getWriter().print("你好");
- 注意:程序运行到响应,那么响应后面的代码应写上return;
- 一次请求对应一次响应,所以response.getWriter.print(“xxx”),里面打印的需要在整个方法执行完才会整体的去响应,在此之前它是将打印的语句储备起来,还未发送响应;所以使用return;进行结尾,那么就可以不让框架继续执行其他,直接返回;
- 使用框架后,request,response这些以后都不经常用了;
- 为什么domain实体类要实现Serializable接口?
- 它是实体类,专门用来存储类,它存在于内存中,实现序列化接口,可以将封装好的类保存到硬盘中,如果突然断电关机什么意外情况,可以反序列化还原;
- 实现该接口,才可以将该对象远程调用,远程传输到其他的服务器,传输时以流的形式
- 实体类中的常见问题:
- 如果实体类中写了有参构造,那么需要再为它创建一个无参构造;
- 成员变量最好使用private修饰,加强安全性,只能通过get,set对其操作;
- 成员变量尽量使用包装类型,不要使用基本类型,即尽量使用Integer类,而不使用int基本类型;
- Integer修饰的变量可以为空,但基本类型不能为null; 比如:private Integer ge=null;
- 请求转发:请求转发是一次请求,不能简写 [手动跳动转发,不会触动视图解析器,需要自己写全路径和文件格式]
-
ModelAndView:
- 把user对象储存到mv对象中,也会把user对象存入到request对象;
- 它既可以储存键值对[发挥model],它也可以转发视图[view]的作用;
- 示例:
* @RequestMapping("/testModelAndView") * public ModelAndView testModelAndView(){ * ModelAndView mv =new ModelAndView(); * System.out.println("testModelAndView方法执行了...") * User user=new User(); * user.setUsername("小枫") * user.setPassword(123); * user.setAge(30); * mv.addObject("user",user); * mv.setViewName("success"); * reutrn mv; * }
- 使用关键字的方式进行转发或者重定向 [使用关键字是不会被视图解析器所管理,需要自己手动补全路径
@RequestMapping("/testForwardOrRedirect") public String testForwardOrRedirect(){ //请求的转发: return "forward:/WEB-INF/pages/success.jsp"; //重定向 return "redirect:/index.jsp"; }
-
ResponseBody响应json数据
- DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置:
- //前端控制前,哪些资源不拦截:
<mvc:resources location="/css/" mapping="/css/**"/> <mvc:resources location="/images/" mapping="/images/**"/> <mvc:resources location="/js/" mapping="/js/**"/>
- 特点:
- mvc:resources标签配置不过滤
- location元素表示webapp目录下的包下的所有文件
- mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
- DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置:
-
模拟示例:
- 模拟异步请求响应:
- 服务器:
@RequestMapping("/testAjax") public void testAjax(@RequestBody String body){ // System.out.println(body); }
- 浏览器:
$(function(){ $("#btn").click(funcation(){ $.ajax({ url:""user/testAjax", contextType:"application/json;charset=UTF-8", //设置了这种格式,提交是以json格式提交,如果不以此设置,$.get |$.post 则都是表单提交格式 data:'{"username":"heihei","password":"123","age":30}', dataType:"json", type:"post", success:function(date){ //data服务器端响应的json数据,进行解析。 } }) })
- 如果传入已经定义好了的domain里User实体类,那么也可以直接传入这个实体类,只要属性值对应的上,那么springmvc就会自动绑定,与ajax发送的属性值一一对应;
- 模拟异步请求响应:
二. 文件上传
2.1 文件上传概述
- 文件上传三要素: [只要是文件上传,就必须满足这三个要素]
- form表单的enctype取值必须是:multipart/form-data
默认值是:application/x-222-form-urlencoded
enctype:是表单请求正文的类型
- method属性必须是post
- get请求会把文件携带在地址栏上,而get请求是有大小限制的;
- 提供一个文件选择域而且必须有name属性:
<input type="file">
- form表单的enctype取值必须是:multipart/form-data
- 借助第三方组件实现文件上传:
导入commons-fileupload-1.3.1.jar和commons-io-2.4.jar
- 案例实现:
2.2 文件上传实战案例
- 搭建开发环境:
1. 创建一个新的maven项目: 坐标,springmvc.xml,web.xml
<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>
- 补全包路径
- 编写文件上传的JSP页面:
<h3>文件上传</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
- 编写文件上传的Controller控制器:
@RequestMapping(value="/fileupload")
public String fileupload(HttpServletRequest request) throws Exception {
// 先获取到要上传的文件目录
String path = request.getSession().getServletContext().getRealPath("/uploads");
// 创建File对象,一会向该路径下上传文件
File file = new File(path);
// 判断路径是否存在,如果不存在,创建该路径
if(!file.exists()) {
file.mkdirs();
}
// 创建磁盘文件项工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 解析request对象
List<FileItem> list = fileUpload.parseRequest(request);
// 遍历
for (FileItem fileItem : list) {
// 判断文件项是普通字段,还是上传的文件
if(fileItem.isFormField()) {
}else {
// 上传文件项
// 获取到上传文件的名称
String filename = fileItem.getName();
// 上传文件
fileItem.write(new File(file, filename));
// 删除临时文件
fileItem.delete();
}
}
return "success";
}
-
SpringMVC实现原理分析:
- 选择文件后点击上传;
- 当文件上传后,通过request进入到前端控制器
- 前端控制器通过添加的配置文件解析器,解析request并返回upload
- 前端控制器调用Controller,将upload传入Controller类下的fileuoload2(MultipartFile upload),然后对其进行操作;
- 注意:前端的name属性值必须和后端Controller类下finduoload2内传入的参数名保持一致;
-
实现代码:
-
SpringMVC传统方式文件上传:
- SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名必须和表单file标签的name属性相同;
- 代码如下:
@RequestMapping(value="/fileupload2") public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception { System.out.println("SpringMVC方式的文件上传..."); // 先获取到要上传的文件目录 String path = request.getSession().getServletContext().getRealPath("/uploads"); // 创建File对象,一会向该路径下上传文件 File file = new File(path); // 判断路径是否存在,如果不存在,创建该路径 if(!file.exists()) { file.mkdirs(); } // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称唯一化 filename = uuid+"_"+filename; // 上传文件 upload.transferTo(new File(file,filename)); return "success"; }
- 配置文件解析器对象: 【如果是传统的文件上传那么会报错,只有SpringMVC的文件上传才能起作用】
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> // 10485760=1024*1024*10=10MB </bean>
-
SpringMVC跨服务器文件上传:
- 搭建图片服务器:
- 根据文档配置tomcat9的服务器,现在是两个服务器
- 导入资料中day02_SpringMVC5_02image项目,作为图片服务器使用 [两个tomcat模拟两台服务器,一台服务器作为控制器接收请求,一台服务器作为图片储存]
- 实现SpringMVC跨服务器文件上传
- 搭建图片服务器:
-
-
导入开发需要的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>
- 编写文件上传JSP页面:
<h3>跨服务器的文件上传</h3> <form action="user/fileupload3" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"/><br/> <input type="submit" value="上传文件"/> </form>
- 编写控制器:
@RequestMapping(value="/fileupload3") public String fileupload3(MultipartFile upload) throws Exception { System.out.println("SpringMVC跨服务器方式的文件上传..."); // 定义图片服务器的请求路径 String path = "http://localhost:9090/day02_springmvc5_02image/uploads/"; // 获取到上传文件的名称 String filename = upload.getOriginalFilename(); String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase(); // 把文件的名称唯一化 filename = uuid+"_"+filename; // 向图片服务器上传文件 // 创建客户端对象 Client client = Client.create(); // 连接图片服务器 WebResource webResource = client.resource(path+filename); // 上传文件 webResource.put(upload.getBytes()); return "success"; }
-
三. 异常处理
3.1 SpringMVC异常处理流程:
- 浏览器-> 前端控制器-> web-> service-> dao
- 如果出现错误,默认处理方案是将错误依次往上抛出:
- 假如dao层出现错误,会抛给service->web->前端控制器->浏览器
- 出现错误如果将错误出现在浏览器上,会降低用户体验,产生不好的影响;
- 此时可在前端控制器添加一个异常处理器组件,它将从内部抛给前端控制器的异常拦截,并将异常进行处理,返回给浏览器一个友好的错误提示页面;
- Controller调用service,service调用dao,异常都是向上抛出的,最终有DispathcherServlet找异常处理器进行异常的处理。
- 示例见下方:
3.2 自定义异常类:
package cn.itcast.exception;
public class SysException extends Exception{
private static final long serialVersionUID = 4055945147128016300L;
// 异常提示信息
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message) {
this.message = message;
}}
3.3 自定义异常处理器
package cn.itcast.exception;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* 异常处理器
* @author rt
*/
public class SysExceptionResolver implements HandlerExceptionResolver{
/**
* 跳转到具体的错误页面的方法
*/
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse
response, Object handler,
Exception ex) {
ex.printStackTrace();
SysException e = null;
// 获取到异常对象
if(ex instanceof SysException) {
e = (SysException) ex;
}else {
e = new SysException("请联系管理员");
}
ModelAndView mv = new ModelAndView();
// 存入错误的提示信息
mv.addObject("message", e.getMessage());
// 跳转的Jsp页面
mv.setViewName("error");
return mv;
}
}
3.4 配置异常处理器:
< bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolvaer"/>
四. 拦截器
- SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理;
- 拦截器链:(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
- 解释:
- 过滤器:是servlet规范中的一部分,任何java web工程都可以使用。
- 拦截器:是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
- 过滤器:是在url-pattern中配置了/*之后,可以对所有要访问的资源拦截;
- 拦截器:它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的。
- 它也是AOP思想的具体应用。
- 我们要想自定义拦截器,要求必须实现:HandlerInterceptor接口。
- 不同点:过滤器什么都拦截,而拦截器只能拦截特定的;即过滤器的范围大于拦截器;
博主还有更多有用的文章哦,有时间的话就点进去翻翻吧,一起进步~