更多内容见:全球顶级java开发面试宝典
SpringMVC常用注解
@RequestMapping进行请求匹配,分发处理匹配的请求,可以作用在类上作整体的请求路径,也可以作用在方法上作更细粒度的请求路径。
@Controller
@RequestMapping("/search/save")
public class ElasticsearchSaveController {
@RequestMapping("/product")
public R productStatusUp() {
}
}
@PostMapping,@GetMapping,@DeleteMapping,@PutMapping等restful风格的请求注解,可以匹配到对应请求类型的路径。如get请求/product和put请求/product可以匹配到对应的@GetMapping(“/product”)和@PutMapping(“/product”)中而无需改多个名字。
@PathVariable用来提取请求路径中变量的值。
@Controller
@RequestMapping("/user/{username}")
public String userProfile(@PathVariable(value="username") String username) {
return "user"+username;
}
@RequestParam则是用来提取请求携带的参数。如/user?blogId=9
@Controller
@RequestMapping(value="/user")
public String getUserBlog(@RequestParam("id") int blogId) {
return blogId;
}
@RequestBody用于接收请求携带的请求体,一般来自post请求,使用对象接收。
@Controller
@RequestMapping("/commit")
public class test{
public void testMethod(@RequestBody User user)"{
}
}
@ResponseBody和@RestController。@ResponseBody用在方法上表示默认将返回值直接放入http的body数据中,@RestController用在类上,表示本类所有的方法都默认执行此行为,在前后端分离常用。
@RestController
public class TestController{
@RequestMapping("/ts")
// @ResponseBody
public String test(){
return "ajax";
}
}
@ModelaAtrribute
SpringMVC执行流程
-
DispatcherServlet调用注册过的BeanNameUrlHandlerMapping(处理映射器)根据请求去查找Handler,并把解析后执行链的信息返回给DispatcherServlet
-
DispatcherServlet调用注册过的SimpleControllerHandlerAdapter(处理适配器)找到对应的Handler去执行并获得它的信息,将信息ModeAndView返回给DispatcherServlet
-
DispatcherServlet调用注册过的InternalResourceViewResolver(视图解析器)对ModelAndView中的数据进行处理,如获得数据和获得视图名并拼接地址,然后把信息返回给DispatcherServlet
-
DispatcherServlet根据视图解析器的结果调用视图渲染呈现
如下图所示
其中组件:
- DispatcherServlet
DispatcherServlet 是前端控制器,Spring MVC的所有请求都要经过 DispatcherServlet 来统一分发。DispatcherServlet 相当于一个转发器或中央处理器,控制整个流程的执行,对各个组件进行统一调度,以降低组件之间的耦合性,有利于组件之间的拓展。 - BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping 是处理器映射器,其作用是根据请求的 URL 路径,通过注解或者 XML 配置,寻找匹配的处理器(Handler)信息。 - SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter 是处理器适配器,其作用是根据映射器找到的处理器(Handler)信息,按照特定规则执行相关的处理器(Handler)。 - Handler
Handler 是处理器,和 Java Servlet 扮演的角色一致。其作用是执行相关的请求处理逻辑,并返回相应的数据和视图信息,将其封装至 ModelAndView 对象中。 - InternalResourceViewResolver
InternalResourceViewResolver 是视图解析器,其作用是进行解析操作,通过 ModelAndView 对象中的 View 信息将逻辑视图名解析成真正的视图 View(如拼接地址通过一个路径返回一个真正的对应页面)。 - ModelAndView
Model是模型,对数据进行存储。View 是视图,其本身是一个接口,实现类支持不同的 View 类型(JSP、FreeMarker、Excel 等)。
SpringMVC基本使用过程
- 在web.xml中配置DispatchServlet,绑定Resource下配置的springmvc-servlet.xml
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value><!-- xml命名:servlet的名字+配置的是个是啥 -->
</init-param>
<load-on-startup>1</load-on-startup> <!--启动级别-->
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern> <!-- / 匹配请求,不会去匹配jsp(jsp直接走页面) /* 匹配所有,包括jsp(匹配jsp过来之后) -->
</servlet-mapping>
- springmvc-servlet.xml中开启包上下文扫描,mvc注解支持,<mvc:default-servlet-handler/>,和视图解析器配置前后缀
<mvc:default-servlet-handler/> <!--让.css,.html,.mp3等什么的去他自己固定的地方-->
<mvc:annotation-driven/> <!--mvc注解支持-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
- 对应类用注解注册为bean,用注解@RequestMapping映射请求,处理后可用ModelAndView存储处理后的数据和返回的视图return回去,也可以直接返回数据或者视图名
@RequestMapping("/get/getProductById")
public ModelAndView getProductById(ModelAndView modelAndView){
modelAndView.addObject(new User());
modelAndView.setViewName("pro");
return modelAndView;
}
@RequestMapping("/getUser")
public String user(Model model){
model.addAttribute("msg",user);
return "First";
}
SpringMVC重定向and转发
重定向和转发在return时进行处理,可用Model携带中间参数。如下图示,在return写好对应的功能即可,同理也可使用ModelAndView写入对对应路径进行请求转发和重定向。
@RequestMapping("/forward")
public String forward(Model model){
model.addAttribute("msg","forward");
return "forward:/WEB-INF/jsp/First.jsp"; //转发,就是普通的return,加了forward和redirect后视图解析器不生效
}
@RequestMapping("/redirect")
public String redirect(Model model){
model.addAttribute("msg","redirect");
return "redirect:index"; //重定向
}
一些区别:
1.重定向访问服务器两次,转发只访问服务器一次。
2.转发页面的URL不会改变,而重定向地址会改变
3.转发只能转发到自己的web应用内,重定向可以重定义到任意资源路径。
4.转发相当于服务器跳转,相当于方法调用,在执行当前文件的过程中转向执行目标文件,两个文件(当前文件和目标文件)属于同一次请求,前后页共用一个request,可以通过此来传递一些数据或者session信息。而重定向会产生一个新的request,不能共享request域信息与请求参数
5.转发相当于同一次请求,可以访问到/WEB-INF目录下的资源,重定向相当于第二次单独请求,不能直接访问/WEB-INF目录下的资源,只得通过controller再次普通return.
SpringMVC拦截器
拦截器在设置完以后,可以对特定的请求路径进行方法执行前方法执行后等处进行拦截,也可以对方法进行限制不予以放行。
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private LoginService loginService;
@Override // 只要用到拦截器,就可以用到拦截器存下的threadlocal
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(!(handler instanceof HandlerMethod)) {
return true;
}
log.info("=================request start===========================");
String requestURI = request.getRequestURI();
log.info("request url:{}",requestURI);
log.info("request method:{}",request.getMethod());
// request.getHeader("xxx");
String token = request.getHeader("Oauth-Token");
System.out.println("浏览器的token:"+token);
System.out.println("整理后+"+token.substring(1,token.length()-1));
log.info("token:{}", token); // 正常是从请求头中取的
log.info("=================request end===========================");
// 如果缓存里没有这个token,可以重定向到主页,以redis过期时间来操作对用户的上线下线
if(StringUtils.isBlank(token)){
Result fail = Result.fail(ErrorCode.NO_LOGIN.getCode(), ErrorCode.NO_LOGIN.getMsg());
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(JSON.toJSONString(fail));
return false;
}
SysUser sysUser = loginService.checkToken(token.substring(1,token.length()-1));
if(sysUser==null){
Result fail = Result.fail(ErrorCode.NO_LOGIN.getCode(), ErrorCode.NO_LOGIN.getMsg());
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(JSON.toJSONString(fail));
return false;
}
// 得到用户信息,方便使用
UserThreadLocal.put(sysUser); // UserThreadLocal建立了一个类,方便去里面拿资源
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 删除ThreadLocal里的信息,防止内存泄漏
UserThreadLocal.remove();
}
}
在xml配置好生效的路径。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/> <!-- /**当前下所有文件包括子文件夹 | /* 当前下文件不包括子文件夹 | /请求 -->
<bean class="com.xin.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
在SpringBoot则统一配置类中进行配置。
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/comments/create/change")
.addPathPatterns("/articles/publish");
}
}
SpringMVC统一异常处理
统一异常处理,顾名思义是对某一处文件所可能抛出的异常进行统一捕获处理,并且可以对不同种类的异常进行不同的处理。但是在使用时不谨慎会有很大的问题,比如应用出异常被捕获没做显眼的处理,导致排错时很难受。
@ControllerAdvice // 对@Controller的类进行aop
public class AllExceptionHandler {
@ExceptionHandler(Exception.class) // 对该种类异常进行捕获
@ResponseBody // 捕获到异常即返回这里的信息
public Result doException(Exception e){
e.printStackTrace();
return Result.fail(-999,"系统异常");
}
}