第五章
5.1控制器的返回值类型
1、String类型
-
返回的字符串,会根据配置好的视图解析器的路径,寻找对应的跳转
-
案例:
-
需求,查询“张三” 的信息,在成功界面输出
-
//主界面jsp文件: <a href="user/textReturnString" >查询张三的信息</a> ---------------------------------------------------------------------------- //控制器: @Controller @RequestMapping("/user") public class UserController { @RequestMapping("/textReturnString") public String textReturnString(Model model){ //模拟在数据库中查询信息 User user = new User(); user.setName("张三"); user.setPassword("123456"); user.setAge(20); //把对象存放到域中,方便在前端jsp页面的使用 model.addAttribute(user); //会跳转到成功界面 return "success"; } } --------------------------------------------------------------------------------- //成功界面 //在jsp页面,想使用EL表达式,取域中的值,先开启jsp页面支持el表达式(isELIgnored="false") <h3>恭喜你访问成功</h3> ${user.toString()}
-
2、void类型
-
没有返回值,默认去找与控制器相同路径的一个页面
,没有该资源,会报404错误 -
怎么解决没有返回值的时候,会报错的问题??
- 方法一:转发的方式指定页面
- 想使用转发,先在控制器的参数中声明一下HttpServletRequest和HttpServletResponse的对象
request.getRequestDispatcher("/WEB-INF/pages/add.jsp").forward(request,response);
- 方法二:重定向的方式指定页面
- 想使用重定向,先在控制器的参数中声明一下HttpServletRequest和HttpServletResponse的对象
response.sendRedirect(request.getContextPath()+"/add2.jsp");
- 转发是一层请求,不用再编写项目名称;而重定向是两次请求,需要写项目的名称
- 利用
request.getContextPath()
方法得到项目的名称
- 方法三:直接响应
- 在控制器上通过输出流的方式,写出jsp的页面代码
- 注意:以上三种方法,不会调用视图解析器
- 方法一:转发的方式指定页面
-
案例源码:
-
<a href="user/textReturnVoid1" >void方式转发方式解决</a><br> <a href="user/textReturnVoid2" >void方式重定向方式解决</a><br> <a href="user/textReturnVoid3" >void方式直接响应方式解决</a><br> ------------------------------------------------------------------------------- //转发 @RequestMapping("/textReturnVoid1") public void textReturnVoid1(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("转发页面执行了"); request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response); } //重定向 @RequestMapping("/textReturnVoid2") public void textReturnVoid2(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("重定向页面执行了"); response.sendRedirect(request.getContextPath()+"/WEB-INF/pages/success.jsp"); } //直接响应 @RequestMapping("/textReturnVoid3") public void textReturnVoid3(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("直接响应页面执行了"); //设置中文乱码 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("恭喜你访问成功"); }
-
3、ModelAndView类型
-
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值
ModelAndView对象相当于两个对象
:Model对象
:该对象和在控制器方法形参中的是一样的(可以往域中存放内容(addObject方法
)等的)View对象
:视图对象,调用setView()
方法,可以设置为哪一个视图
- 当ModelAndView对象做为控制器的返回值的时候,会自动的根据配置的视图解析器,寻找设置的那个视图的位置
-
案例:
-
<a href="user/textReturnModelAndView">查询张三的信息</a> --------------------------------------------------------------------------- //返回值为ModelAndView @RequestMapping("/textReturnModelAndView") public ModelAndView textReturnModelAndView(){ ModelAndView mv = new ModelAndView(); //在数据库中查询到的张三的信息 User user = new User(); user.setName("张三"); user.setPassword("123456"); user.setAge(20); //存放到域对象中 mv.addObject("user",user); //设置指向的页面 mv.setViewName("success"); return mv; }
-
5.2 SpringMVC提供的转发和重定向关键字
-
如果不想使用视图解析器,而且控制器方法的返回值还是String类型的,怎么办??
-
通过Spring提供的两个关键字,可以实现支付串拼接的转发或者重定向
转发关键字:" forward: 路径 "
- **它相当于 request.getRequestDispatcher(“url”).forward(request,response) **
- **使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法 **
重定向关键字:" redirect: 路径 "
- **它相当于 response.sendRedirect(url) **
- 需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不能写在 WEB-INF 目录中,否则无法找到。
-
案例源码:
-
<a href="user/textSpringMVCForward">SpringMVC关键字进行转发</a> <a href="user/textSpringMVCRedirect">SpringMVC关键字进行重定向</a> -------------------------------------------------------------------------------- //SpringMVC关键字进行转发 @RequestMapping("/textSpringMVCForward") public String textSpringMVCForward(){ System.out.println("SpringMVC关键字进行转发方法执行了"); return "forward:/WEB-INF/pages/success.jsp"; } //SpringMVC关键字进行重定向 @RequestMapping("/textSpringMVCRedirect") public String textSpringMVCRedirect(){ System.out.println("SpringMVC关键字进行重定向方法执行了"); return "redirect: /WEB-INF/pages/success.jsp"; }
-
5.3 ResponseBody响应 JSON 数据
1、(重点) DispatcherServlet控制器会拦截静态资源,导致一个问题
-
问题的分析:
DispatcherServlet会拦截到所有的资源(可以看一下控制器的配置)
,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。
-
问题的解决:
- 需要
配置静态资源不进行拦截,在SpringMVC.xml配置文件添加如下配置
- 需要
-
如何配置:
-
在SpringMVC.xml文件上进行配置 < mvc:resources/>标签
-
< mvc:resources/>
标签- location属性: 在webapp目录下的包下的静态资源的位置
- 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/**"/>
-
-
-
-
参考其他处理方式:
2、发送json数据请求,并使用@RequestBody获取json数据
(先导入JQuery的静态资源,或者在Maven的坐标中导入JQuery)
<!--通过ajax发送请求数据 -->
<%--按钮--%>
<input id="button" type="button" value="发送请求"/>
<%--引入JQuery--%>
<script type="text/javascript" class="/js/jquery-3.5.1.min.js"></script>
<%--发送ajax--%>
<script>
$("#button").click(function (){
$.ajax({
url: "user/textJson",
contentType:"application/json;charset=UTF-8",
data:{"name":"张三","password":"12345","age":18},
dataType:"json",
type:"post",
success:function (data) {
//服务器对返回的json数据进行处理
alert(data);
}
});
});
</script>
//控制器方法
@RequestMapping("/textJson")
//将整个json请求体都封装到body参数中去(通过@RequestBody注解)
public String textJson(@RequestBody String body){
System.out.println(body);
return "success";
}
3、 json字符串和JavaBean对象互相转换的过程中,需要使用jackson的jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
4、怎么把发送过来的Json数据,封装到相应的对象中??
-
SpringMVC帮我们提供了Json数据转为JavaBean对象,但是要
导入Jackson的jar包
-
通过@RequestBody注解,在控制器的参数直接把数据传给对应的对象
-
@RequestMapping("/textJson") //@RequestBody注解,将整个json请求体都封装到body参数中去 //我们得到Json可以可以通过java的API进行对数据的解析 //SpringMVC会自动帮我们封装到响应的对象中(前提是json中的键的名称和对象的属性名相同) public String textJson(@RequestBody User user){ System.out.println(user); return "success"; }
5、 使用@ResponseBody注解
把JavaBean对象转换成json字符串,直接响应
-
在返回值上加上
@ResponseBody 注解
,把返回值类型的对象,转为Json的格式返回去 -
//@ResponseBody注解,会把返回舱去的User对象数据,转为Json的格式 public @ResponseBody User textJson3(@RequestBody User user){ System.out.println(user); User newUser = new User(); newUser.setName("李四"); newUser.setAge(22); newUser.setPassword("56789"); return newUser; }
第六章 文件的上传
1、传统方式文件上传回顾
-
导入上传文件的jar包
-
<!--上传文件的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>
-
-
表单上传文件的要求:
-
form 表单的 enctype 取值必须是:multipart/form-data
- 默认的application/x-www-form-urlencoded是以键值对的方式上传
- multipart/form-data 是以分段的形式上传文件
-
(默认值是:application/x-www-form-urlencoded)
-
enctype:是表单请求正文的类型
-
<form action="user/textFileUpload" method="post" enctype="multipart/form-data"> 选择文件:<input type="file" name="upload"><br/> <input type="submit" value="提交"> </form>
-
-
Servlet控制器的处理:
-
@RequestMapping("/textFileUpload") public String textFileUpload(HttpServletRequest request) throws Exception { System.out.println("文件上传"); //1、文件上传的位置 //1、1拿到要上传文件夹的路径 String path = request.getSession().getServletContext().getRealPath("/uploads/"); //1、2判断该路径是否存在?? File file = new File(path); if (!file.exists()) { //不存在的话,创建该目录 file.mkdirs(); } //2、解析request对象,获取到上传的文件项(根据提供的jar包解析) //2、1创建磁盘文件项工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); //2、2解析request(里面全是放的文件项),完成文件的上传 List<FileItem> items = upload.parseRequest(request); //遍历文件项 for (FileItem item : items) { //拿到每一个文件项,进行判断,判断当前的文件项是否是上传文件项 //判断文件项是普通字段,还是上传的文件 if (item.isFormField()) { //如果是true说明是一个普通的表单项 } else { //如果是false说明是一个上传文件项 //拿到上传文件的名(注意同名文件会把文件替换了) String fileName = item.getName(); //把文件名称设置为唯一值uuid String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); fileName=fileName+uuid; //完成文件的上传 item.write(new File(path, fileName)); //删除临时文件 item.delete(); } } return "success"; }
-
2、SpringMVC方式的文件上传
2.1 原理:
- 通过
文件解析器(MultipartFile对象)
的一个组件 - 在控制器的参数中,传入文件解析器对象
- 注意:
表单的name名称
和控制器中文件上传项参数名 必须一样
2.2 配置文件解析器对象
-
在SpringMVC.xml文件中配置其Bean对象
-
在该Bean对象中可以设置很多的上传要求:最大文件大小(maxUploadSize)等等
-
注意:
文件解析器的id必须为:multipartResolver
-
<!-- 配置文件解析器对象,要求id名称必须是multipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="10485760"/> </bean>
-
2.3 源码:
-
jsp代码:
-
<form action="user/textSpringMVCFileUpload" method="post" enctype="multipart/form-data"> <h3>SpringMVC方式文件上传</h3> 选择文件:<input type="file" name="upload"><br> <input type="submit" value="提交"> </form>
-
控制器源码:
-
@RequestMapping("/textSpringMVCFileUpload") public String textSpringMVCFileUpload(HttpServletRequest request,MultipartFile upload) throws IOException { //1、文件上传的位置 //1、1拿到要上传文件夹的路径 String path = request.getSession().getServletContext().getRealPath("/uploads/"); //1、2判断该路径是否存在?? File file = new File(path); if (!file.exists()) { //不存在的话,创建该目录 file.mkdirs(); } //不用再自己进行解析文件了,拿到的upload就是SpringMVC的文件解析器已将帮忙解析好的文件 //拿到上传的名称 String filename = upload.getOriginalFilename(); //把名字设为唯一值(通过uuid方式,也可以使用时间戳) String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); filename=uuid+"-"+filename; //完成文件的上传 upload.transferTo(new File(path,filename)); //临时文件SpringMVC帮我们自动删除了 return "success"; }
-
3、SpringMVC跨服务器方式的文件上传
3.1 分服务器的目的??
- 在实际开发中,我们会有很多处理不同功能的服务器。
- 例如:
- 应用服务器:负责部署我们的应用
- 数据库服务器:运行我们的数据库
- 缓存和消息服务器:负责处理大并发访问的缓存和消息
- 文件服务器:负责存储用户上传文件的服务器。
- ( 注意:此处说的不是服务器集群)
- 分服务器处理的目的是让服务器各司其职,从而提高我们项目 的运行效率。
3.2 所需要的的jar包
和两个服务器的准备
(搭建环境)
-
需要的jar包:
-
-
对应的Maven的坐标
-
<!--跨服务器方式上传--> <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>
-
-
-
创建两个服务器
创建一个存放图片的项目,部署到一个服务器上(图片服务器)
创建另一个项目(写源码的项目),部署到服务器上(应用服务器)
3.3 SpringMVC跨服务器上传文件源码
-
前端jsp页面:
-
<form action="user/textSpringMVCSericerFileUpload" method="post" enctype="multipart/form-data"> <h3>SpringMVC跨服务器方式文件上传</h3> 选择文件:<input type="file" name="upload"><br> <input type="submit" value="提交"> </form>
-
-
控制器:
-
@RequestMapping("/textSpringMVCSericerFileUpload") public String textSpringMVCSericerFileUpload(MultipartFile upload) throws Exception{ //定义上传服务器的路径(注意:后面写个斜杠,进行分离) //传到改路径下 String path="http://localhost:9090/springmvc_image/uploads"; //上传文件名称 String filename = upload.getOriginalFilename(); //名称唯一 String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase(); filename=uuid + "-"+filename; //使用导入的jar包,完成跨服务器的上传 //1、创建客户端的对象 Client client = Client.create(); //2、与图片服务器进行连接 WebResource webResource = client.resource(path + filename); //3、调用方法上传文件 webResource.put(upload.getBytes()); return "success"; }
-