目录
一:SpringBoot 和 web组件
1. SpringBoot中使用拦截器(重点)
2. SpringBoot中使用Servlet
3. SpringBoot中使用过滤器(重点)
4. 字符集过滤器的应用
一:SpringBoot 和 web组件
1. SpringBoot中使用拦截器Interceptor(重点)
拦截器是SpringMVC中一种对象,能够拦截器对Controller的请求!
拦截器框架中有系统的拦截器, 还可以自定义拦截器, 实现对请求预先处理!
实现自定义拦截器:
第一步:创建一个类实现SpringMVC框架的HandlerInterceptor接口,重写方法。
HandlerInterceptor接口源码中有三个默认方法,常用的是preHandle方法中进行拦截:
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
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 {
}
}
编写LoginInterceptor类实现HandlerInterceptor接口,并重写preHandler方法
package com.zl.web;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 自定义拦截器
public class LoginInterceptor 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 { // handler是被拦截的控制器对象
System.out.println("请求拦截器执行了");
return false;
}
}
第二步:SpringBoot中注册声明拦截器
SpringMVC框架中注册声明拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:path="url" />
<bean class="拦截器类全限定名称"/>
</mvc:interceptor>
</mvc:interceptors>
SpringBoot框架中注册声明拦截器
(1)使用类+注解的方式,编写一个类实现WebMvcConfigurer接口(这个接口很重要,后面会讲),并添加@Configuration注解,关于SpringMVC有关的功能都在WebMvcConfigurer接口中实现了!
(2)重写addInterceptors方法,在方法中添加拦截器对象,注入到容器当中;然后在调用addPathPatterns添加拦截的请求,再调用excludePathPatterns排除拦截的请求。
package com.zl.config;
import com.zl.web.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration // 这个类当做配置文件使用
public class MyAppConfigurer implements WebMvcConfigurer {
// 添加拦截器对象,注入到容器中
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 创建拦截器对象
HandlerInterceptor interceptor = new LoginInterceptor();
// 调用addInterceptor方法表示注入到容器中
// 调用addPathPatterns方法表示可以拦截的请求
// 调用excludePathPatterns方法表示通过的请求
registry.addInterceptor(interceptor)
.addPathPatterns("/user/**")
.excludePathPatterns("/user/login");
}
}
第三步:编写controller进行访问
package com.zl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BootController {
@RequestMapping("/user/account") // 会被拦截
@ResponseBody
public String userAccount(){
return "访问user/account地址";
}
@RequestMapping("/user/login")
@ResponseBody
public String userLogin(){
return "访问user/login地址"; // 会被通过
}
2. SpringBoot中使用Servlet
在SpringBoot框架中使用Servlet对象!
使用步骤:
②创建Servlet类继承HttpServlet类。
②注册Servlet ,让框架能找到Servlet。
第一步:创建Servlet类继承HttpServlet
重写doGet和doPost方法,并且在doGet中调用doPost方法,这样不论发过来post请求还是get请求都没有问题!
package com.zl.web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 调用doPost方法
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 使用HttpServletResponse输出数据,应答结果
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("执行的是Servlet");
out.flush();
out.close();
}
}
第二步:注册Servlet ,让框架能找到Servlet
(1)ServletRegistrationBean用来做在 servlet 3.0+容器中注册 servlet 的功能,但更具有 SpringBean友好性。
(2)首先写一个类,类名随意,加上@Configuration注解,表示这个类是配置信息的类;再类中编写一个servletRegistrationBean()方法,返回值是ServletRegistrationBean对象
(3)添加上@Bean注解。@Bean用于将对象存入spring的ioc容器中,同@controller、@Service、@Component、@Configuration、@Repository等几个注解是一样的,都是负责将对象存入容器当中。只不过方式不同,四个注解它们是用在类上面的,然后将当前类通过无参构造函数创建对象然后放入容器;而@Bean是用在方法上,将当前方法的返回值对象放到容器当中!可以理解为前者是由spring自动创建对象,而@Bean创建对象是交给我们自己来控制。
package com.zl.config;
import com.zl.web.MyServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServlet;
@Configuration
public class WebAppConfig {
// 定义方法,注册Servlet对象
@Bean // 把ServletRegistrationBean对象放到容器当中
public ServletRegistrationBean servletRegistrationBean(){
// 创建ServletRegistrationBean对象,有两个参数:
// 一个参数是servlet,一个参数是url地址
HttpServlet servlet = new MyServlet();
ServletRegistrationBean bean = new ServletRegistrationBean(servlet,"/myservlet");
return bean;
}
}
当然也可以使用无参数构造方法,调用引用.set方法进行赋值,对于路径也可以赋多个
ServletRegistrationBean bean = new ServletRegistrationBean();
bean.setServlet(servlet);
bean.addUrlMappings("/login","/test"); // 多个路径都可以访问
3. SpringBoot中使用过滤器Filter(重点)
Filter是Servlet规范中的过滤器,可以处理请求、对请求的参数、属性进行调整; 常常在过滤器中处理字符编码。
使用步骤:
①创建自定义过滤器类;
②注册Filter过滤器对象;
注:对于过滤器和拦截器的简单理解
(1)过滤器是用来过滤request或者response参数的(比如:增加一些乱码),侧重于对数据的过滤;
(2)而拦截器是用来验证请求的,能够截断请求!
第一步:创建自定义过滤器类
创建MyFilter类实现Filter接口,重写doFilter方法,进行处理;处理好以后调用filterChain参数的doFilter方法,把请求传递出去,继续进行下一步操作。
package com.zl.web;
import javax.servlet.*;
import java.io.IOException;
// 自定义过滤器类
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// 处理字符集编码
response.setContentType("text/html;charset=UTF-8");
System.out.println("Filter过滤器执行了");
// 把请求转发出去
filterChain.doFilter(request,response);
}
}
第二步:注册过滤器对象
写一个配置类,类名随意,加上@Configuration注解,表示这个类是配置信息的类;再类中编写一个filterRegistrationBean()方法,返回值是FilterRegistrationBean对象,并在方法上加上@Bean注解,把返回的对象交给Spring容器管理。
package com.zl.config;
import com.zl.web.MyFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.FilterRegistration;
@Configuration
public class WebApplicationConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean (){
// 调用无参数构造方法
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new MyFilter()); // 指定过滤器对象
bean.addUrlPatterns("/user/*"); // 指定过滤的地址
return bean;
}
}
编写controller进行访问
package com.zl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class CustomerFilterController {
@RequestMapping("/user/account")
@ResponseBody
public String userAccount(){
return "user/account执行了";
}
}
4. 字符集过滤器的应用
CharacterEncodingFilter:解决post请求中乱码的问题;在SpringMVC框架, 在web.xml注册过滤器,配置它的属性,解决乱码问题!
创建一个Servlet
package com.zl.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("在Servlet中使用中文");
out.flush();
out.close();
}
}
注册Servlet
package com.zl.web;
import com.zl.servlet.MyServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
@Controller
public class WebAppConfig {
// 注册Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
MyServlet myServlet = new MyServlet();
ServletRegistrationBean bean = new ServletRegistrationBean(myServlet, "/myservlet");
return bean;
}
}
进行访问:发现中文乱码
F12,刷新请求并打开,发现默认的编码方式是:ISO-8859-1
第一种解决方式:自定义过滤器,比较麻烦,不推荐
①在注册Servlet中添加过滤器
package com.zl.web;
import com.zl.servlet.MyServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.filter.CharacterEncodingFilter;
@Controller
public class WebAppConfig {
// 注册Servlet
@Bean
public ServletRegistrationBean servletRegistrationBean(){
MyServlet myServlet = new MyServlet();
ServletRegistrationBean bean = new ServletRegistrationBean(myServlet, "/myservlet");
return bean;
}
// 注册Filter
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean bean = new FilterRegistrationBean();
// 使用框架中的过滤器
CharacterEncodingFilter filter = new CharacterEncodingFilter();
// 指定使用的编码方式
filter.setEncoding("UTF-8");
// 指定request,response使用encoding的值
filter.setForceEncoding(true);
// 给filter设置参数
bean.setFilter(filter);
bean.addUrlPatterns("/*"); // 过滤所有的地址
return bean;
}
}
②修改application.properties文件, 让自定义的过滤器起作用
#SpringBoot中默认已经配置启用了CharacterEncodingFilter,编码默认ISO-8859-1
#设置enabled=false 作用是关闭系统中配置好的过滤器, 使用自定义的CharacterEncodingFilter
server.servlet.encoding.enabled=false
第二种方式:直接使用框架中的过滤器,比较简单,推荐使用
注:实际上SpringBoot已经把字符编码的过滤器自动纳入容器管理了,通过源码分析可以发现这个配置与配置文件application.properties中的server.servlet.encoding配置进行了绑定。
package org.springframework.boot.autoconfigure.web.servlet;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Encoding;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;
@AutoConfiguration
@EnableConfigurationProperties({ServerProperties.class})
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
// 自动装入了容器中去
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
return filter;
}
@Bean
public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
return new LocaleCharsetMappingsCustomizer(this.properties);
}
static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
private final Encoding properties;
LocaleCharsetMappingsCustomizer(Encoding properties) {
this.properties = properties;
}
public void customize(ConfigurableServletWebServerFactory factory) {
if (this.properties.getMapping() != null) {
factory.setLocaleCharsetMappings(this.properties.getMapping());
}
}
public int getOrder() {
return 0;
}
}
}
直接修改application.properties文件进行更改
#让系统的CharacterEncdoingFilter生效,默认就是开启的,不写也行
server.servlet.encoding.enabled=true
#指定使用的编码方式
server.servlet.encoding.charset=utf-8
#强制request,response都使用charset属性的值
server.servlet.encoding.force=true