URL 地址映射
@RequestMapping 注解:注解在控制器类或者控制器类的方法上
- 注解在控制类上,会将一个特定的请求或请求模式映射到一个控制器上
注解在控制器类的方法上
@RestController
// 注解在方法上,即 http://localhost:8080/demo/** 会被映射到此控制器
@RequestMapping("/demo")
public class DemoController {
// 访问路径:http://localhost:8080/demo
@RequestMapping
public String demo(){
return "demo";
}
// 即访问路径为: 主机+端口/应用路径/类路径/方法路径
// 访问路径:http://localhost:8080/demo/d01
@RequestMapping(value = "/d01")
public String demo01(){
return "d01";
}
// 支持绑定多个URL
@RequestMapping(value = {"/d02","/d03"})
public String demo02(){
return "d02";
}
}
@RequestMapping 参数说明:
- value:指定请求的实际地址
- method:请求的 method 类型,参数为 RequestMethod 枚举类的实例,常用的有
- RequestMethod.GET
- RequestMethod.POST
- RequestMethod.PUT
- RequestMethod.DELETE
- consumes:指定处理请求提交的内容类型(Content-Type),可以使用字符串或 MediaType 类的静态变量来指定
- produces:指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回,可以使用字符串或 MediaType 类的静态变量来指定
- params:指定 request 中必须包含某些参数值时,才让该方法处理
- headers:指定 reques 中必须包含某些指定的 header 值,才能让该方法处理请求
其他衍生注解:
- @GetMapping
- @PostMapping
- @DeleteMapping
- @PutMapping
参数绑定
1、基本类型:
- 请求参数要和方法的形参同名即可正确传参
- 如果需要设置参数的更多细节,可以使用 @RequestParam 注解
@RequestParam:将请求参数绑定到控制器方法的参数上(是 SpringMVC 中接受普通参数的注解)
- value:参数名
- required:是否包含该参数,默认为 true,表示该请求路径中必须包含该参数,如果不包含就报错
- defaultValue:默认参数值,如果设置了该值,required = true 将失效,自动设置为 false,如果没有传递该参数,就使用默认值
// http://localhost:8080/bind/p01?age=15&money=12.6&gender=true
// 如果未设置默认值,某个参数未传会报500服务器异常
@RequestMapping("/p01")
public void p01(@RequestParam(defaultValue = "10") int age,
@RequestParam(defaultValue = "12.5") double money,
@RequestParam(defaultValue = "false") boolean gender) {
System.out.println("age = " + age);
System.out.println("money = " + money);
System.out.println("gender = " + gender);
}
2、基本类型的包装类型和 String 类型:
- 请求参数要和控制器中的方法参数名一致,当某个参数未传入时,该参数为 null
- 使用 @RequestParam 注解指定更多细节
// http://localhost:8080/bind/p02?age=15&money=12.6&gender=true
// 如果参数未传,该参数会被设置为null而不报错
@RequestMapping("/p02")
public void p02(Integer age,
Double money,
Boolean gender) {
System.out.println("age = " + age);
System.out.println("money = " + money);
System.out.println("gender = " + gender);
}
// 访问http://localhost:8080/bind/p02,输出
age = null
money = null
gender = null
3、数组参数绑定:简单类型的数组
// http://localhost:8080/bind/p03?ints=12&ints=13&ints=14
// 传参形式:ints=1&ints=2
@RequestMapping("/p03")
public void p03(Integer[] ints) {
System.out.println(Arrays.toString(ints));
}
4、JavaBean 参数绑定:
- 请求参数和实体的属性字段同名 ```java @Data public class User { private Integer id; private String name; private Boolean gender; }
// http://localhost:8080/bind/p04?id=1&name=李四&gender=false @GetMapping(“/p04”) public void p04(User user) { System.out.println(user); }
5、List、Set、Map 集合类型参数绑定
- 需要绑定在对象上,而不能直接写在 Controller 方法的参数中
- set 和 map 在进行绑定时必须先创建对象
```java
@Data
static class User {
List<String> hobby;
Set<String> sets = new HashSet<>();
Map<String, String> maps = new HashMap<>();
}
// http://localhost:8080/bind/p05?hobby=basketball&hobby=baseball&sets=hello&sets=world&maps[ni]=shijie&maps[wang]=da
// List参数:hobby=basketball&hobby=baseball
// Set参数:sets=hello&sets=world
// Map参数:maps[ni]=shijie&maps[wang]=da
@RequestMapping("/p05")
public void p05(User user) {
System.out.println(user.getHobby());
System.out.println(user.getSets());
System.out.println(user.getMaps());
}
控制台输出:
请求转发与重定向
静态页面的访问:
- 静态页面不应该被直接访问,应该由前端控制器进行请求转发
- 静态页面应该放在 WEB-INF 目录下,强制不接受外界直接访问,只能由控制器请求转发访问,此时重定向无法直接访问静态页面,需要新增一个静态页面跳转的请求转发控制器
参数值的传递:控制器得到数据后,向视图层传递数据,从而可以在视图层进行渲染,使用户看到含有数据的页面
- 请求转发:使用 Request 作用域
- 重定向跳转:使用 Session 作用域
请求转发与重定向:
- 在增删改之后,为了防止请求重复提交,重定向跳转
- 在查询之后,可以作转发跳转
请求转发与重定向:
1、请求转发:
- 使用 HttpServletRequest 的 request.getRequestDispatcher(“views/index.jsp”).forward(req, resp);
- 使用 ViewResolver 进行跳转,即返回字符串
ModelAndView 请求转发 ```java @Controller @RequestMapping(“/views”) public class ViewController { @RequestMapping(“/forward01”) public String forward01() {
// 跳转到绝对路径,即以 / 开头的路径,即 webapp/index.jsp 页面
// 如果使用相对路径,跳转的路径会带上类上的路径,即 /views/ + 跳转
return "forward:/index.jsp?username=直接转发";
}
@RequestMapping(“/forward02”) public ModelAndView forward02() {
ModelAndView mv = new ModelAndView();
// ModelAndView:模型和视图对象
// mv.addObject()添加参数在请求转发时会放到Request域中
mv.setViewName("forward:/index.jsp?username=请求转发");
return mv;
} }
// 路径中的参数可以在 jsp 中通过 ${param.username} 进行获取 // Request域中的参数可以通过 ${requestScope.xxx} 进行获取
2、重定向:两次请求,在SpringMVC支持多种重定向方式
- 使用 HttpServletResponse 类的 response.sendRedirect() 方法
```java
@RequestMapping(value="/redirect01",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView redirect01(HttpServletResponse response){
response.sendRedirect("/index");
return null;
}
- ViewResolver 直接跳转重定向
```java
// 不带参数
@RequestMapping(value=”/redirect02”,method = { RequestMethod.POST, RequestMethod.GET })
public String redirect02(){
return “redirect:/index”;
}
// 带参数 @RequestMapping(“/redirect03”) public String redirect03(Model model, RedirectAttributes redirectAttributes) { // 重定向如果参数中存在中文,此时可能会出现乱码,通过声明 RedirectAttributes 类型参数,携带重定向参数 // 使用 RedirectAttributes 的 addAttribute 方法传递参数会跟随在URL后面 redirectAttributes.addAttribute(“username”, “世界”);
// Model.addFlashAttribute()不会跟随在URL后面,而是将该参数值暂时保存于Session,待重定向url获取该参数后从session中删除
// 注意此方法的redirect必须是方法映射路径,不能是jsp
attr.addFlashAttribute("key", "value");
return "redirect:/api/user";
}
- ModelAndView 重定向
```java
// 不带参数
@RequestMapping(value="/redirect04",method = { RequestMethod.POST, RequestMethod.GET })
public ModelAndView redirect04(){
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:/index.jsp");
return mv;
}
// 带参数
@RequestMapping("/redirect05")
public String redirect05() {
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:/index.jsp");
// 当视图对象为请求转发时,addObject添加的参数会添加到路径中
mv.addObject("username","重定向");
return mv;
}
参数传递
1、参数值传递:
参数值存到 Request 域:
- ModelAndView:返回值 ModelAndView
- ModelMap:返回值为 String
- Model:返回值为 String
- Map:返回值为 String
- HttpServletRequest:返回值为 String
参数值存到 Session 域:
HttpSession
@Controller
@RequestMapping("/views")
public class ViewController {
// http://localhost:8080/views/index
@GetMapping("/index")
public ModelAndView toIndex() {
/**
* 模型数据:Model
* 视图信息:View
*/
ModelAndView mv = new ModelAndView();
// 添加属性
mv.addObject("username", "世界之窗");
// 绑定视图
mv.setViewName("index");
return mv;
}
// http://localhost:8080/views/index/01
@GetMapping("/index/01")
public String toIndex01(Model model) {
// 通过Model进行设置
model.addAttribute("username", "世界之窗1");
return "index";
}
// http://localhost:8080/views/index/02
@GetMapping(value = "/index/02")
public String toIndex02(HttpServletRequest request) {
// 在Request域中设置属性
request.setAttribute("username", "世界之窗2");
return "index";
}
// http://localhost:8080/views/index/03
@GetMapping(value = "/index/03")
public String toIndex03(ModelMap map) {
// 通过ModelMap进行设置
map.addAttribute("username", "世界之窗3");
return "index";
}
// http://localhost:8080/views/index/04
@GetMapping(value = "/index/04")
public String toIndex04(Map<String, Object> map) {
// 通过Map进行设置
map.put("username", "世界之窗4");
return "index";
}
}
2、在 index.jsp 中获取:${username}
静态资源映射
tomcat 存在一个默认的 defaultServlet 来处理静态资源,然而在 Spring MVC 中配置了 dispatcherServlet 拦截了所有的请求,所以静态资源无法访问
1、DispatcherServlet 采用其他的 url-pattern(如 .action、.do),如所有的 handler 的路径都以 action 结尾,即在 web.xml 中对 DispatcherServlet 作如下配置:
<!-- 前端控制器 -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- 指定配置文件的位置 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 在web部署的时候初始化该servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 使用前端控制器分发do结尾的请求 -->
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2、静态资源:
- DispatcherServlet 的 url-pattern 依然采用”/“,但追加配置,额外增加一个 handler ,且其 requestMapping 为 /**,可以匹配所有请求,但优先级最低
- 因此其他所有的 handler 都无法匹配时,请求转向该 handler
在spring-mvc.xml中增加如下配置:
<!-- 配置静态资源访问 -->
<mvc:default-servlet-handler/>
3、配置 /xx/** 将静态资源文件映射到 ResourceHttpRequestHandler 进行处理
<mvc:resources mapping="/js/**" location="/WEB-INF/views/js/"/>
<mvc:resources mapping="/css/**" location="/WEB-INF/views/css/"/>
4、激活 tomcat 的 defaultServlet 来处理静态文件:
在 web.xml 中配置如下映射,default 为 tomcat 默认的 Servlet
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
中文乱码解决
1、前端页面中字符集统一:
JSP:<%@ page contentType="text/html;charset=UTF-8" language="java" %>
HTML:<meta charset="UTF-8">
2、在tomcat的 server.xml 中进行设置:
<Connector port="8080" redirectPort="8443" connectionTimeout="20000" protocol="HTTP/1.1" URIEncoding="utf-8"/>
3、在 web.xml 中配置一个设置编码的 filter ,对 post 请求中,中文参数乱码有效
- SpringMVC 为我们提供了这样一个类,无需自己实现
等效于:<!-- 配置文件编码过滤器 -->
<filter>
<filter-name>encoding</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<!-- 对全部请求进行过滤 -->
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
// 在获取参数前,设置request的编码与页面编码一致,一般写在filter中
req.setCharacterEncoding("utf-8");
// 响应双端的编码设置
response.setContentType("text/html;charset=UTF-8");