3. Web 组件
2022年9月6日
3. Web 组件
拦截器, Servlet , Filter
拦截器
拦截器是 SpringMVC 中一种对象, 能拦截器对 Controller 的请求.
拦截器框架中有系统的拦截器, 还可以自定义拦截器, 实现对请求预先处理.
SpringMVC 拦截器:
创建类实现 SpringMVC 框架的 HandlerInterceptor 接口
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
需在 SpringMVC 的配置文件中, 声明拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:path="url" /> <bean class="拦截器类全限定名称"/> </mvc:interceptor> </mvc:interceptors>
SpringBoot 中注册拦截器:
需要实现
WebMvcConfigurer
接口, 该接口集成了 MVC 中 xml 配置文件的相关配置
WebMvcConfigurer
源码
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
default void addFormatters(FormatterRegistry registry) {}
default void addInterceptors(InterceptorRegistry registry) {}
default void addResourceHandlers(ResourceHandlerRegistry registry) {}
default void addCorsMappings(CorsRegistry registry) {}
default void addViewControllers(ViewControllerRegistry registry) {}
default void configureViewResolvers(ViewResolverRegistry registry) {}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
编写一个拦截器类
public class LoginHandler implements HandlerInterceptor {
/**
* @param request
* @param response
* @param handler 被拦截的控制器对象
* @return boolean
* true: 请求能被controller处理
* false: 请求被截断
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginHandler.preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
在配置类实现 WebMvcConfigurer
接口
@Configuration
public class MyAppConfig implements WebMvcConfigurer {
//添加拦截器对象, 注入到容器中
@Override
public void addInterceptors(InterceptorRegistry registry) {
//创建拦截器对象, 也可以使用注解将该类交给 spring 容器管理
HandlerInterceptor interceptor = new LoginHandler();
//指定拦截的请求uri地址
String path []= {"/user/**"};
//指定不拦截的地址
String excludePath [] = {"/user/login"};
registry.addInterceptor(interceptor)
.addPathPatterns(path)
.excludePathPatterns(excludePath);
}
}
在 controller 层测试访问
@Controller
public class HelloController {
@RequestMapping("/user/account")
@ResponseBody
public String userAccount() {
return "userAccount"; // 无打印输出
}
@RequestMapping("/user/login")
@ResponseBody
public String userLogin() {
return "userLogin"; // 打印输出 "LoginHandler.preHandle"
}
}
Servlet
在 SpringBoot 框架中使用 Servlet 对象.
使用步骤:
- 创建 Servlet 类, 创建类继承 HttpServlet
- 注册 Servlet, 让框架能找到 Servlet
创建自定义 Servlet
//创建Servlet类 public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 在doGet() 方法中调用了doPost() 方法, get和post操作结果一样, 仅方便测试 doPost(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //使用HttpServletResponse输出数据, 应答结果 resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.println("===执行的是Servlet=="); out.flush(); out.close(); } }
注册 Servlet
@Configuration public class WebApplictionConfig { // 定义方法, 注册Servlet对象 @Bean public ServletRegistrationBean<MyServlet> servletRegistrationBean() { /* public ServletRegistrationBean(T servlet, String... urlMappings) 第一个参数是 Servlet对象, 第二个是url地址 ServletRegistrationBean bean = new ServletRegistrationBean( new MyServlet(),"/myservlet"); */ ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(); bean.setServlet(new MyServlet()); bean.addUrlMappings("/login", "/test"); // <url-pattern> return bean; }
访问测试
过滤器 Filter
Filter 是 Servlet 规范中的过滤器, 可以处理请求, 对请求的参数, 属性进行调整, 常常在过滤器中处理字符编码.
在框架中使用过滤器:
- 创建自定义过滤器类
- 注册 Filter 过滤器对象
例子:
// 自定义过滤器
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("执行了MyFilter, doFilter");
filterChain.doFilter(servletRequest,servletResponse);
}
}
注册 Filter
@Configuration
public class WebApplicationConfig {
@Bean
public FilterRegistrationBean<MyFilter> filterRegistrationBean(){
FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
bean.setFilter( new MyFilter());
bean.addUrlPatterns("/user/*");
return bean;
}
}
在 controller 中访问测试
@Controller
public class HelloController {
@RequestMapping("/user/account")
@ResponseBody
public String userAccount() {
return "user account";
}
}
运行结果
过滤器和之前的拦截器都生效了, 且过滤器在前
字符集过滤器
CharacterEncodingFilter
: 解决 post 请求中乱码的问题
如果在 servlet 中不指定 HttpServletResponse 的响应的字符集, 则默认为 ISO-8859-1.
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 在doGet() 方法中调用了doPost() 方法, get和post操作结果一样, 仅方便测试
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 使用HttpServletResponse输出数据, 应答结果
resp.setContentType("text/html"); // 不指定字符集 ;charset=utf-8
PrintWriter out = resp.getWriter();
out.println("===执行的是Servlet==");
out.flush();
out.close();
}
}
在 SpringMVC 框架, 在 web.xml 注册过滤器. 配置他的属性.
第一种方式:
配置字符集过滤器
@Configuration public class WebSystemConfig { // 注册Servlet @Bean public ServletRegistrationBean servletRegistrationBean(){ MyServlet myServlet = new MyServlet(); ServletRegistrationBean reg = new ServletRegistrationBean(myServlet,"/myservlet"); return reg; } // 注册Filter @Bean public FilterRegistrationBean<CharacterEncodingFilter> filterRegistrationBean() { FilterRegistrationBean<CharacterEncodingFilter> reg = new FilterRegistrationBean<>(); // 使用框架中的过滤器类 CharacterEncodingFilter filter = new CharacterEncodingFilter(); // 指定使用的编码方式 filter.setEncoding("utf-8"); // 指定request, response都使用encoding的值 filter.setForceEncoding(true); reg.setFilter(filter); // 指定 过滤的url地址 reg.addUrlPatterns("/*"); return reg; } }
修改 application.properties 文件, 让自定义的过滤器起作用
#SpringBoot中默认已经配置了CharacterEncodingFilter. 编码默认ISO-8859-1 #设置enabled=false 作用是关闭系统中配置好的过滤器, 使用自定义的CharacterEncodingFilter server.servlet.encoding.enabled=false
第二种方式:
修改 application.properties 文件
#让系统的CharacterEncodingFilter生效
server.servlet.encoding.enabled=true
#指定使用的编码方式
server.servlet.encoding.charset=utf-8
#强制request, response都使用charset属性的值
server.servlet.encoding.force=true