1、控制器方法的返回值类型
(1)返回的是字符串类型:用返回的字符串和配置的视图解析器一起,跳转到指定的页面;
(2)没有返回值(void):可以用原生的Servlet的请求转发或重定向到其他页面;
(3)返回值是ModelAndView类型,,用setViewName方法指定跳转页面!!
测试:
springmvc.xml:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="cn.melo"></context:component-scan>
<!--配置视图解析器-->
<bean id="viewResolver" 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-driven/>
</beans>
index.jsp:
控制器类:
PersonController.java:
package cn.melo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author hejm
* @date 2019/11/20
*/
@Controller
@RequestMapping(path = "/person")
public class PersonController {
@RequestMapping(path = "/test1")
public String test1(){
System.out.println("返回值是字符串!!");
return "success";
}
@RequestMapping(path = "/test2")
public void test2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("返回值是void!!");
request.getRequestDispatcher("/hello.jsp").forward(request,response);
}
@RequestMapping(path = "/test3")
public ModelAndView test3(ModelAndView mav){
//指定跳转路径
mav.setViewName("success");
//添加携带的对象
mav.addObject("xx","XX");
return mav;
}
}
页面结构:
测试结果:
都能跳转成功,而且还可以用${requestScope.xx}
取出ModelAndView中存储的对象!
2、springMVC提供的请求转发和请求重定向
如果控制器方法的返回值是字符串,可以在字符串前面加上"forward:"(表示请求转发)或者是"redirect:"(表示请求重定向)!
当然也可以用servlet的原始api搞定!
3、DispatcherServlet拦截静态资源的问题
DispatcherServlet会拦截所有资源,导致一些静态资源(img,js,css)也会被拦截,从而不能使用,解决这个问题就是在springmvc.xml中配置<mvc:resources>
即可:
location表示webapp目录下的所有文件;
mapping表示以/static开头的所有请求路径!
4、@RequestBody和@ResponseBody
(1)@RequestBody可以写在处理器方法的形参前面,可以获取请求体数据
(2)@ResponseBody写在控制器方法上(或者方法的返回值前面),可以把JavaBean转化成json直接响应,要求方法的返回值类型是JavaBean,且要引入jackson的核心包和依赖包;
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.0</version>
</dependency>
测试:
实体类:
person.java:
package cn.melo.bean;
/**
* @author hejm
* @date 2019/11/20
*/
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.4.1.js"></script>
<script type="text/javascript">
$(function() {
$("#bt1").click(function () {
$.ajax({
url: "person/testJson",
type: "POST",
dataType: "JSON",
success: function(data){
alert(data.name + "------" +data.age);
alert(JSON.stringify(data)); //将json对象转换成字符串)
},
sync: true
});
});
});
</script>
</head>
<body>
<button id="bt1">点击获取json数据</button>
</body>
</html>
控制器类中的方法:
@RequestMapping(path = "/testJson")
@ResponseBody
public Person testJson(){
Person person = new Person("melo",18);
return person;
}
结果:
5、springMVC文件上传问题:
(1)步骤:
A、引入fileupload和io包:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
(2)写上传页面,要求提交方式必须是post,enctype属性为:“multipart/form-data”
<form action="person/fileupload" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="name">
文件:<input type="file" name="file">
<input type="submit" value="提交">
</form>
(3)Controller编写:springMVC提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须与表单中type的值是file的标签的name属性值相同:
@RequestMapping(path = "/fileupload")
public String fileupload(MultipartFile file,String name) throws IOException {
System.out.println("name:"+name);
String fileName = file.getOriginalFilename();
System.out.println("fileName:"+fileName);//得到文件名称
String uuid = UUID.randomUUID().toString().replaceAll("-","")
.toUpperCase();
String newFileName = uuid + "_" + fileName; //给文件取一个新名字
File f = new File("E:/"+newFileName);//保存图片
file.transferTo(f);
return "success";
}
(4)在springmvc.xml中配置文件解析器对象,要求这个bean的id必须是multipartResolver:
<!--配置文件解析器对象,要求id值必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件的最大大小是5M 单位是bytes -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
ok,测试结果:
6、springMVC文跨服务器方式上传文件
(1)搭建两个服务器,当然要改掉其中一个的端口号;
(2)有两个项目,每个项目对应一个服务器!
首先Tomcat默认情况下是只读的,所以要去tomcat的目录下的conf文件夹下找到web.xml文件,在servlet-name是default的那个下面添加一个配制:
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
还要创建文件上传表单和在springmvc.xml中创建文件解析器对象,和上面文件上传是一样的!
除了文件上传需要的io和fileupload的包之外,还要导入两个jersey的jar包:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19.4</version>
</dependency>
控制器类:
@RequestMapping("/fileupload")
public String fileupload(MultipartFile file) throws IOException {
//获取文件名
String fileName = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString().replaceAll("-","")
.toUpperCase();
//给文件取新名字
String newFileName = uuid + "_" + fileName;
//把文件放到另一个项目(fileupload)的upload这个目录下面
String path = "http://localhost:9090/fileupload/upload/";
//创建客户端对象
Client client = Client.create();
//连接另一个服务器
WebResource resource = client.resource(path+newFileName);
//上传文件
String s = resource.put(String.class,file.getBytes());
System.out.println(s);
System.out.println("跨服务器图片上传成功!!");
return "success";
}
在fileupload项目的target/fileupload目录创建一个文件夹叫upload!
测试:
7、springMVC的异常处理
(1)Controller调用Service,Service调用dao,异常都是向上抛的,最终会由DispatcherServlet找异常处理器对异常进行处理!
(2)自定义异常处理的步骤:
A、创建一个异常类:UserException.java
package cn.melo.exception;
/**
* @author hejm
* @date 2019/11/21
*/
public class UserException extends Exception {
private String message;
public UserException(String message){
this.message = message;
}
public String getMessage(){
return this.message;
}
}
B、定义一个异常处理类实现HandlerExceptionResolver接口,重写resolveException方法;
package cn.melo.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author hejm
* @date 2019/11/21
*/
public class MyExceptionReolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject("error",e.getMessage());
return modelAndView;
}
}
C、写异常页面:error.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1 style="color: red">出错啦!!!</h1>
<h3>${requestScope.error}</h3>
</body>
</html>
D、在springmvc.xml中配置异常处理器类!
<!--配置自定义异常处理器类-->
<bean id="myExceptionReolver" class="cn.melo.exception.MyExceptionReolver"></bean>
测试:
页面:
Controller类:
@RequestMapping(path = "/testException/{id}")
public String testException(@PathVariable(value = "id") String id) throws UserException {
if(id.equals("7")) {
throw new UserException("用户异常!!");
}
return "success";
}
测试结果:
6、springMVC中的拦截器
(1)拦截器和过滤器的功能比较相似,区别在于:
A、过滤器是Servlet规范的一部分,任何框架都可以用过滤器技术;
拦截器是springMVC独有的
C、过滤器配置了/*以后可以拦截任何资源
拦截器只会拦截控制器类中的控制器方法!
拦截器也是一种AOP思想的体现!
(2)自定义拦截器步骤:
A、创建类,实现HandlerInterceptor接口,重写preHandle方法,return true表示放行,return false表示拦截!
package cn.melo.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author hejm
* @date 2019/11/21
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("被拦截了!!!");
return false;
}
}
B、在spingmvc.xml中配置拦截器:
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截的路径-->
<mvc:mapping path="/testInterceptor/7"/>
<!--表示不拦截的路径-->
<mvc:exclude-mapping path="/testInterceptor/1"/>
<bean id="myInterceptor" class="cn.melo.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
C、Controller:
@RequestMapping(path = "/testInterceptor/{id}")
public String testInterceptor(@PathVariable(value = "id") String id){
System.out.println(id);
return "success";
}
测试:
(3)HandlerInterceptor中的方法:
A、preHandle:在控制器方法执行前执行:
可以用request跳转到指定页面;
return true;表示放行,如果还有拦截器就执行下一个拦截器,否则就执行要访问的控制器方法!
return falese;表示拦截此次请求,不会执行控制器方法!
B、postHandle:是在控制器方法执行之后,在视图执行之前执行的
可以用request或者response跳转页面,如果跳转了页面,那么控制器方法返回的页面就不会显示!
C、afterCompletion:在视图执行完之后执行,可以在该方法中进行一些资源清理的操作。不能再用request或者response跳转页面!
注意:如果配置了多个拦截器,会按照配置的顺序执行拦截器!!!