入门案例 1
核心DispatcherServlet如何配置
HandlerMapping
HandlerAdapter
Handler
application.xml → DispatcherServlet启动的时候加载这个配置文件
引入依赖
SpringMVC:spring-web、spring-webmvc、servlet-api(provided)
配置成idea中的标准web应用
首先在pom.xml中写这句代码:
先进webapp目录,webapp目录下新建WEB-INF目录。WEB-INF目录下新建web.xml。
配置DispatcherServlet
我们之前说dispatchServlet会处理所有的请求,那么url-pattern这里是否要写/*呢?
不写,应当写成/。
dispatchServlet的/是经过特殊处理的,它不会去解析jsp、html相关的请求,除此之外所有的请求都进行拦截。
加载xml配置文件
得加载Spring容器,注册组件,HandlerMapping、HandlerAdapter、Handler这些组件。
要通过application.xml去加载容器。
要在DispatcherServlet初始化的时候加载xml配置文件。
而Servlet什么时候加载?在第一次我们访问url-pattern的时候。
注册组件
HandlerMapping、HandlerAdapter、Handler这些组件
我们需要把Handler作为一个组件注册在容器中,这个组件需要我们去实现。
入门案例2
依然要配置成SpringMVC的web应用
依然要去注册组件HandlerMapping、HandlerAdapter
handler相关的组件发生了变化,handler不再以组件的形式存在了,而是以方法的形式存,handler方法仍然是要和请求url建立映射关系
搭建成一个SpringMVC的web应用
同上
配置SpringMVC容器中的组件
RequestMapping
RequestMappingHandlerMapping
RequestMappingHandlerAdapter
不用去写bean标签注册
这一行代码能够注册必需的组件。
注册controller组件
handler方法在controller组件中存在
业务:访问/hello → songge niupi ligenli daqi
handler方法中返回的ModelAndView → viewName:hello.jsp → content:ligenli daqi
handler方法可以单独的和url映射起来,这就是一个解耦操作,我们可以在这个类中处理很多个请求。而不是像案例一,一个类只能处理一个请求。
接下来的内容都是围绕handler展开的
一、@RequestMapping注解
补充:将多个请求url映射到同一个handler方法上
方法一:
value接收的是一个字符串数组,它可以接收多个url。
方法二:可以使用*来通配
*可以代替一个单词或一个单词的一部分
接下来redeploy一下,在写JavaEE项目的时候,只需要更新一下class就好了,这次为什么的redeploy呢?
我们是把UrlMappingController作为容器中的组件,加载application.xml配置文件的时候,其实通过init-param就初始化了容器,容器中是单例,也就是说容器初始化的时候,组件生命周期就开始了,才注册了组件,所以不能通过更新class去更新代码。
二、窄化请求映射
比如 user相关的请求(handler方法),都放在UserController这个组件中
对应的请求url都是和user相关的
user/insert、user/delete、user/update
之前都是写在handler方法的@RequestMapping注解的value中,能否把user提取出来,只写insert、delete、update呢?
常见错误:
@Controller做的是组件注册,@RequestMapping做的才是窄化请求。
三、请求方法限定 (405)
请求方法即:RequestMethod → get、post 这些
在@RequestMapping注解这个增加method属性
当请求方法和限定方法不一致:
限定的方法是post,也就是说get方法不允许。
限定多个请求方法(or)
3.1.3.3引申的注解
@GetMapping → @RequestMapping(method=GET)
@PostMapping→ @RequestMapping(method=POST)
@PostMapping和@RequestMapping源码:
四、请求参数限定
仍然是在@RequestMapping的注解中写param属性
五、请求header限定
handler的返回值
a. void
如何配置model参数,如何设置视图view
使用request和response(其实就相当于之前的doGet和doPost方法)
这个并不建议使用,这相当于开历史的倒车,我们又去使用底层的request和response方法了。
b. ModelAndView
c. String
返回这个字符串的含义是什么?
(1). 物理视图名
→ viewName
我们的model怎么办? → model放入handler方法的形参,传入的是接口Model。
Model的addAttribute方法和前面写的ModelAndView类的addObject方法是一样的。
(2). 逻辑视图名
何为逻辑视图名?
物理视图名中我们写了一个"/WEB-INF/view/string.jsp"这样的返回值,我们的返回值不想写这么多,只想写一个string(/WEB-INF/view/string.jsp中的string),这时候可以使用逻辑视图名。
需要去配置组件:viewResolver
那么配置了视图解析器viewResolver,有何影响
modelAndView中viewName会拼接
在上面物理视图名的案例中返回值也会受影响 → 也就是所有的返回值为字符串都会做一个拼接
(3). 转发重定向
字符串来进行转发和重定向
转发和重定向的是请求,而不是jsp
也就是说下面代码中的forward Handler方法 和 redirect handler方法都是将请求转发到hello handler方法中,hello handler方法的返回值为viewName,浏览器又会去访问http://localhost:8080/return/view/hello页面。
2. 不处理视图层(json)→ 非常重要
前后端分离,视图层的开发交给前端来做
返回值类型 可以写成Object,Object最终呈现的就是json数据
依赖+@ResponseBody注解(或者@RestController)
a. 导包
jackson
b. handler方法上增加@ResponseBody
引申一个注解@RestController
handler形参
请求参数的封装
a. 直接写在handler方法的形参上
String、基本类型、包装
String username,int age,Boolean married
在这里明明jsp页面输入的age和username是String类型的,可是却能用int和、boolean类型的值接收,这是SpringMVC帮我们转换的。
b. 封装为javabean
javabean的成员变量名 和请求参数名一致
c. 多级javabean(嵌套javabean)
d. 数组数据和list
Post请求乱码问题
写一个filter:CharacterEncodingFilter
filter放在web.xml中进行配置。
init-param标签其实调用的就是CharacterEncodingFilter 的set方法。
附上CharacterEncodingFilter 的代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.web.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
public class CharacterEncodingFilter extends OncePerRequestFilter {
@Nullable
private String encoding;
private boolean forceRequestEncoding;
private boolean forceResponseEncoding;
public CharacterEncodingFilter() {
this.forceRequestEncoding = false;
this.forceResponseEncoding = false;
}
public CharacterEncodingFilter(String encoding) {
this(encoding, false);
}
public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
this(encoding, forceEncoding, forceEncoding);
}
public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
this.forceRequestEncoding = false;
this.forceResponseEncoding = false;
Assert.hasLength(encoding, "Encoding must not be empty");
this.encoding = encoding;
this.forceRequestEncoding = forceRequestEncoding;
this.forceResponseEncoding = forceResponseEncoding;
}
public void setEncoding(@Nullable String encoding) {
this.encoding = encoding;
}
@Nullable
public String getEncoding() {
return this.encoding;
}
public void setForceEncoding(boolean forceEncoding) {
this.forceRequestEncoding = forceEncoding;
this.forceResponseEncoding = forceEncoding;
}
public void setForceRequestEncoding(boolean forceRequestEncoding) {
this.forceRequestEncoding = forceRequestEncoding;
}
public boolean isForceRequestEncoding() {
return this.forceRequestEncoding;
}
public void setForceResponseEncoding(boolean forceResponseEncoding) {
this.forceResponseEncoding = forceResponseEncoding;
}
public boolean isForceResponseEncoding() {
return this.forceResponseEncoding;
}
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = this.getEncoding();
if (encoding != null) {
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}
if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}
filterChain.doFilter(request, response);
}
}
附录:
复制文件的时候注意
复制完的文件有的时候idea不会自动编译
要去检查 war exploded的output path(target/artifactId-version) 文件是否有编译过去
如果没有编译过去,就删除掉重新启动,让他重新编译 → 如果还没有编译过去,手动复制粘贴过去
看到的是网页源代码。选择preview就会显示的和浏览器中一样
不写的话就是啥请求都可以接收
作业:下面注册页面使用springmvc实现
不要关注表单的美观度(注意侧重点放在构造表单上,不要放在美观上)
1、增加个人爱好字段,需要至少有三个选项
2、不需要关注验证码图片的回显
注册页面中的所有类型使用springmvc框架获取请求参数.
作业2的图片资源:
代码见Homework07
首先访问http://localhost:8080/register.jsp,然后提交
接下来就会跳转到以下界面:
作业3 springmvc 封装多级JavaBean
如果User里有Teacher引用,Teacher里又有Course引用。
这种情况下springmvc是否可以封装完成。
并测试你的结论。
代码见Homework07
首先访问http://localhost:8080/student/jsp
然后提交
然后跳转到以下界面: