Обучение технологиям на рабочем месте является самым быстрым и глубоким. Конечно, самосознание непрерывного обучения является обязательным.
Версия технического стека:
spring boot 2.0.2
что-то произошло
В последнее время для хозяйственных нужд фронтенд одноклассник Fe будетuserId
иuserName
ставитьrequest header
бинго. Внутренний API-интерфейс хочет использоватьuserId
иuserName
, каждый интерфейс должен начинаться сheader
получено в. Представьте, если у вас есть десять интерфейсов, вам нужно написать каждый интерфейсObject.setUserId(request.getHeader("userId"))
. как следующий фрагмент кода
@RestController
@Validated
@RequestMapping("/template")
public class TemplateController {
// 一个feign client
@Autowired
TemplateClient templateClient
@PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE)
public ResultVO create(@RequestBody @Valid TemplateParam param, HttpServletRequest request) {
// 每个接口都要写一遍setXXX()方法
param.setUserId(request.getHeader("userId"));
param.setUserName(request.getHeader("userName"));
return templateClient.createTemplate(param).toResultVO();
}
}
@Data
public class TemplateParam{
private Long templateId;
private Long userId;
private String userName;
}
Решение
Мы все знаем два великих оружия,
Фильтр tomcat и Intercepter spring (в частности, HandlerIntercepter)
Принцип реализации
Конкретный метод заключается в определении класса реализации Filter и класса реализации HandlerIntercepter. Определите другой класс реализации HttpServletRequest, функции которого
Класс реализации фильтра: UserInfoFilter
Создайте запись и определите возможность в этой записи: передайте наш пользовательский CustomHttpServletRequestWrapper вместо HttpServletRequest с запросом
Класс реализации HttpServletRequest: customHttpServletRequestWrapper
Поскольку данные тела объекта HttpServletRequest могут быть только получены, не могут быть установлены, то есть не могут быть повторно назначены. Наше требование заключается в необходимости назначения HttpServletRequest, вам необходимо определить класс, который реализует HttpServletRequest: customHttpServletRequestWrapper, класс реализации может быть назначен для удовлетворения наших потребностей.
Класс реализации HandlerIntercepter: Custominterceptor
Перехватывать запросы и получать информацию, связанную с методом интерфейса (имя метода, параметры, возвращаемое значение и т. д.). Для достижения единого динамического назначения тела запроса
Идея реализации описана выше, а конкретный код реализации выглядит следующим образом.
Код
Объявить базовый компонент: UserInfoParam
UserInfoParam: определяет объектный компонент, содержащий userId и userName. Чтобы внедрить в него информацию о пользователе, входной объект XXXParam должен наследовать UserInfoParam, а перехватчик обрабатывает только компоненты, которые реализуют класс UserInfoParam в @Requestbody. В качестве входного параметра метода создания в контроллере выше: TemplateParam, наследует UserInfoParam
@Data
public class TemplateParam extends UserInfoParam{
private Long templateId;
// private Long userId;
// private String userName;
}
@Data public class UserInfoParam {
// 用户id
private Long userId;
// 用户名称
private String userName;
}
Определите класс реализации фильтра: UserInfoFilter.
@Slf4j
public class UserInfoFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
CustomHttpServletRequestWrapper customHttpServletRequestWrapper = null;
try {
HttpServletRequest req = (HttpServletRequest)request;
customHttpServletRequestWrapper = new CustomHttpServletRequestWrapper(req);
}catch (Exception e){
log.warn("customHttpServletRequestWrapper Error:", e);
}
chain.doFilter((Objects.isNull(customHttpServletRequestWrapper) ? request : customHttpServletRequestWrapper), response);
}
}
Класс реализации HTTPSERVLETREQUEST: CustomhttpServletRequestWrapper
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
// 保存request body的数据
private String body;
// 解析request的inputStream(即body)数据,转成字符串
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
// 赋值给body字段
public void setBody(String body) {
this.body = body;
}
}
Класс реализации HandlerIntercepter: CustomInterceptor
@Slf4j
public class CustomInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod)handler;
pushUserInfo2Body(request, handlerMethod);
return true;
}
private void pushUserInfo2Body(HttpServletRequest request, HandlerMethod handlerMethod) {
try{
String userId = request.getHeader("userId");
String userName = request.getHeader("userName");
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
if(ArrayUtils.isEmpty(methodParameters)) {
return;
}
for (MethodParameter methodParameter : methodParameters) {
Class clazz = methodParameter.getParameterType();
if(ClassUtils.isAssignable(UserInfoParam.class, clazz)){
if(request instanceof CustomHttpServletRequestWrapper){
CustomHttpServletRequestWrapper requestWrapper = (CustomHttpServletRequestWrapper)request;
String body = requestWrapper.getBody();
JSONObject param = JSONObject.parseObject(body);
param.put("userId", userId);
param.put("userName", Objects.isNull(userName) ? null : URLDecoder.decode(userName, "UTF-8"));
requestWrapper.setBody(JSON.toJSONString(param));
}
}
}
}catch (Exception e){
log.warn("fill userInfo to request body Error ", e);
}
}
Определите класс Configuration, добавьте конфигурацию перехватчиков и фильтров
Подкласс WebMvcConfigurer: CustomWebMvcConfigurer
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
CustomInterceptor customInterceptor= new CustomInterceptor();
registry.addInterceptor(customInterceptor);
}
@Bean
public FilterRegistrationBean servletRegistrationBean() {
UserInfoFilter userInfoFilter = new UserInfoFilter();
FilterRegistrationBean<UserInfoFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(userInfoFilter);
bean.setName("userInfoFilter");
bean.addUrlPatterns("/*");
bean.setOrder(Ordered.LOWEST_PRECEDENCE);
return bean;
}
}
На этом код для реализации функции закончен. Запустите приложение весенней загрузки, вы можете свернуть, чтобы получить доступ к спокойному интерфейсу.
http-доступ
curl -X POST \
http://localhost:8080/template/create
-H 'Content-Type: application/json'
-H 'username: tiankong天空'
-H 'userId: 11'
-d '{
"templateId": 1000}
Эффект
Вы можете увидеть информацию, напечатанную TemplateController.create(...), значения userId и username точно соответствуют значениям, переданным в заголовке
toDo
Остальное зависит от тебя
Оригинальный адрес:Перехватчик Springboot HandlerIntercepter реализует модификацию данных тела запроса