版权声明:文章为作者自己原创文章,转载请注明出处。 https://blog.csdn.net/qq_37128049/article/details/83449384
今日内容:
1. 响应
2. 文件上传
3. 异常处理
4. 拦截器[作用不大了,了解]
响应
1. 概述:就是把后台的数据返回给浏览器/用户;
2. 搭建环境:
1. 创建项目:Maven->选择骨架或者手动添加.. 在main中创建java,resources,webapp三个包,webapp包下创建WEB-INF,pages:创建succes.jsp;[成功的返回页面]
2. 导入相关坐标.. [可以应用版本锁定]
3. 引入前端控制器[固定写法]
4. springmvc.xml:开启注解扫描,视图解析器,注解支持
5. 删除webapp中的index.jsp重新创建一个;
3. 响应数据和结果视图:
1. Controller方法返回字符串 【使用Model存入数据再返回】
1. 解析: Controller方法执行后,返回的字符串根据视图解析器所前后拼接的文件名和地址,就能成功的跳转到所需的页面;
2. 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";
* }
* }
2. Controller方法返回void 【return;】
1. 请求转发:请求转发是一次请求,不能简写 [手动跳动转发,不会触动视图解析器,需要自己写全路径和文件格式]
* 示例:request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
2. 重定向:请求转发是可以直接访问web-inf下的文件,所以不用写虚拟地址;
* reponse.sendRedirect(request.getContextPath()+"WEB-INF/pages/xxx.jsp")
3. 解决中文乱码:
* reponse.setCharacterEncoding("UTF-8");
* response.setContentType("text/html;charset=UTF-8");
4. 直接响应:
* response.getWriter().print("你好");
5. 注意:程序运行到响应,那么响应后面的代码应写上return;
* 一次请求对应一次响应,所以response.getWriter.print("xxx"),里面打印的需要在整个方法执行完才会整体的去响应,在此之前它是将打印的语句储备起来,还未发送响应;所以使用return;进行结尾,那么就可以不让框架继续执行其他,直接返回;
6. 使用框架后,request,response这些以后都不经常用了;
7. 为什么domain实体类要实现Serializable接口?
* 它是实体类,专门用来存储类,它存在于内存中,实现序列化接口,可以将封装好的类保存到硬盘中,如果突然断电关机什么意外情况,可以反序列化还原;
* 实现该接口,才可以将该对象远程调用,远程传输到其他的服务器,传输时以流的形式
8. 实体类中的常见问题:
1. 如果实体类中写了有参构造,那么需要再为它创建一个无参构造;
2. 成员变量最好使用private修饰,加强安全性,只能通过get,set对其操作;
3. 成员变量尽量使用包装类型,不要使用基本类型,即尽量使用Integer类,而不使用int基本类型;
4. Integer修饰的变量可以为空,但基本类型不能为null; 比如:private Integer ge=null;
3. ModelAndView:
1. 把user对象储存到mv对象中,也会把user对象存入到request对象;
2. 它既可以储存键值对[发挥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;
* }
4. 使用关键字的方式进行转发或者重定向 [使用关键字是不会被视图解析器所管理,需要自己手动补全路径]
* @RequestMapping("/testForwardOrRedirect")
* public String testForwardOrRedirect(){
* //请求的转发:
* return "forward:/WEB-INF/pages/success.jsp";
* //重定向
* return "redirect:/index.jsp";
* }
4. ResponseBody响应json数据
1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。解决问题就是需要配置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置:
* //前端控制前,哪些资源不拦截:
* <mvc:resources location="/css/" mapping="/css/**"/>
* <mvc:resources location="/images/" mapping="/images/**"/>
* <mvc:resources location="/js/" mapping="/js/**"/>
2. 特点:
1. mvc:resources标签配置不过滤
2. location元素表示webapp目录下的包下的所有文件
3. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
5. 模拟示例:
1. 模拟异步请求响应:
1. 服务器:
* @RequestMapping("/testAjax")
* public void testAjax(@RequestBody String body){
* //
* System.out.println(body);
* }
2. 浏览器:
* $(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数据,进行解析。
* }
* })
* })
3. 如果传入已经定义好了的domain里User实体类,那么也可以直接传入这个实体类,只要属性值对应的上,那么springmvc就会自动绑定,与ajax发送的属性值一一对应;
文件上传
1. 文件上传三要素: [只要是文件上传,就必须满足这三个要素]
1. form表单的enctype取值必须是:multipart/form-data
* [默认值是:application/x-222-form-urlencoded]
* enctype:是表单请求正文的类型
2. method属性必须是post
* get请求会把文件携带在地址栏上,而get请求是有大小限制的;
3. 提供一个文件选择域而且必须有name属性:
* <input type="file">
2. 借助第三方组件实现文件上传:
* 导入commons-fileupload-1.3.1.jar和commons-io-2.4.jar
3. 案例实现:
1. 搭建开发环境:
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>
2. 补全包路径
3. 编写文件上传的JSP页面:
<h3>文件上传</h3>
<form action="user/fileupload" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
4. 编写文件上传的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";
}
5. SpringMVC实现原理分析:
1. 选择文件后点击上传;
2. 当文件上传后,通过request进入到前端控制器
3. 前端控制器通过添加的配置文件解析器,解析request并返回upload
4. 前端控制器调用Controller,将upload传入Controller类下的fileuoload2(MultipartFile upload),然后对其进行操作;
5. 注意:前端的name属性值必须和后端Controller类下finduoload2内传入的参数名保持一致;
6. 实现代码:
1. SpringMVC传统方式文件上传:
1. SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名必须和表单file标签的name属性相同;
2. 代码如下:
@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";
}
3. 配置文件解析器对象: 【如果是传统的文件上传那么会报错,只有SpringMVC的文件上传才能起作用】
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"/> // 10485760=1024*1024*10=10MB
</bean>
2. SpringMVC跨服务器文件上传:
1. 搭建图片服务器:
1. 根据文档配置tomcat9的服务器,现在是两个服务器
2. 导入资料中day02_SpringMVC5_02image项目,作为图片服务器使用 [两个tomcat模拟两台服务器,一台服务器作为控制器接收请求,一台服务器作为图片储存]
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页面:
<h3>跨服务器的文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传文件"/>
</form>
3. 编写控制器:
@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";
}
异常处理
1. SpringMVC异常处理流程:
1. 浏览器-> 前端控制器-> web-> service-> dao
2. 如果出现错误,默认处理方案是将错误依次往上抛出:
* 假如dao层出现错误,会抛给service->web->前端控制器->浏览器
3. 出现错误如果将错误出现在浏览器上,会降低用户体验,产生不好的影响;
* 此时可在前端控制器添加一个异常处理器组件,它将从内部抛给前端控制器的异常拦截,并将异常进行处理,返回给浏览器一个友好的错误提示页面;
4. Controller调用service,service调用dao,异常都是向上抛出的,最终有DispathcherServlet找异常处理器进行异常的处理。
5. 示例:
1. 自定义异常类:
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;
}}
2. 自定义异常处理器
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. 配置异常处理器:
< bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolvaer"/>
拦截器
1. SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理;
2. 拦截器链:(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
3. 解释:
* 过滤器:是servlet规范中的一部分,任何java web工程都可以使用。
* 拦截器:是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
* 过滤器:是在url-pattern中配置了/*之后,可以对所有要访问的资源拦截;
* 拦截器:它是只会拦截访问的控制器方法,如果访问的是jsp,html,css,image或者js是不会进行拦截的。
* 它也是AOP思想的具体应用。
* 我们要想自定义拦截器,要求必须实现:HandlerInterceptor接口。
4. 不同点:过滤器什么都拦截,而拦截器只能拦截特定的;即过滤器的范围大于拦截器;