在控制器之前使用拦截器编辑对象的值

huangapple go评论60阅读模式
英文:

Edit values of object with Interceptor before the controller

问题

有没有选项在请求传递到控制器之前使用拦截器编辑值?

我尝试包装HttpServletRequest并设置新的body。

在控制器中有一个如下所示的Post请求:

@PostMapping("/edit-via-interceptor")
public MyObject getNewObjectFromInterceptor(@RequestBody MyObject myObject){
    return myObject;
}

对象看起来像这样:

@Data
public class MyObject implements Serializable {
    private List<String> ids;
}

RequestBody中有一个ids列表,我想在拦截器中向当前列表添加2个默认的id。

拦截器看起来像这样:

@Component
public class Interceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpServletRequest httpRequest = request;

        CustomHttpServletRequestWrapper wrapper = new CustomHttpServletRequestWrapper(httpRequest);
        ObjectMapper objectMapper = new ObjectMapper();

        MyObject newMyObject =  objectMapper.readValue(wrapper.getInputStream(), MyObject.class);
        List<String> newIdsList = newMyObject.getIds();
        newIdsList.add("123");
        newIdsList.add("1234");
        newMyObject.setIds(newIdsList);
        byte[] data = SerializationUtils.serialize(newMyObject);
        wrapper.setBody(data);

        return super.preHandle(wrapper, response, handler);
    }
}

CustomHttpServletRequestWrapper看起来像这样:

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public CustomHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            body = IOUtils.toByteArray(request.getInputStream());
        } catch (IOException ex) {
            body = new byte[0];
        }
    }

    public void setBody(byte[] body){
        this.body = body;
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStream() {
            ByteArrayInputStream bais = new ByteArrayInputStream(body);

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {

            }
        };
    }
}

拦截器模式的配置:

@Configuration
public class AuthConfig implements WebMvcConfigurer {

    @Autowired
    private Interceptor controllerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // The registration of /api/** must be in the end
       
        registry.addInterceptor(controllerInterceptor).addPathPatterns("/**");
    }
}

在所有这些之后,当到达控制器时,MyObject为null。

英文:

there any option to edit values with Interceptor before the request goes to the controller?

I tried to wrap the HttpServletRequest and set the new body.

I have Post request in controller that looks like this :

@PostMapping(&quot;/edit-via-interceptor&quot;)
public MyObject getNewObjectFromInterceptor(@RequestBody MyObject myObject){
    return myObject;}

The Object looks like this:

@Data
public class MyObject implements Serializable {
    private List&lt;String&gt; ids;
}

The RequestBody has List of ids, and I want to add inside the interceptor 2 default id's to the current list.

The Interceptor looks like this:

@Component
public class Interceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpServletRequest httpRequest = request;

        CustomHttpServletRequestWrapper wrapper = new CustomHttpServletRequestWrapper(httpRequest);
        ObjectMapper objectMapper = new ObjectMapper();

        MyObject newMyObject =  objectMapper.readValue(wrapper.getInputStream(), MyObject.class);
        List&lt;String&gt; newIdsList = newMyObject.getIds();
        newIdsList.add(&quot;123&quot;);
        newIdsList.add(&quot;1234&quot;);
        newMyObject.setIds(newIdsList);
        byte[] data = SerializationUtils.serialize(newMyObject);
        wrapper.setBody(data);

        return super.preHandle(wrapper, response, handler);
    }
}

CustomHttpServletRequestWrapper looks like this:

public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private byte[] body;

    public CustomHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            body = IOUtils.toByteArray(request.getInputStream());
        } catch (IOException ex) {
            body = new byte[0];
        }
    }

    public void setBody(byte[] body){
        this.body = body;
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new ServletInputStream() {
            ByteArrayInputStream bais = new ByteArrayInputStream(body);

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {

            }
        };
    }
}

The configuration on Interceptor pattern :

@Configuration
public class AuthConfig implements WebMvcConfigurer {

    @Autowired
    private Interceptor controllerInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // The registration of /api/** must be in the end
       
        registry.addInterceptor(controllerInterceptor).addPathPatterns(&quot;/**&quot;);
    }

After all that, When its comes to the Controller - MyObject is null.

答案1

得分: 3

我使用@Around注解进行了相同的操作。这是文档6.2.4.5. Around advice(在访问链接后需要搜索 @around)。您可以修改请求和响应。

还有@Before@After建议,如果需要的话,您也可以使用。如果您只需要在控制器调用之前访问对象,@Before应该足够了。

@Aspect
@Component
public class RequestModifierAspect {
    
    @Around("execution(* com.example.YourController.methodName(..))")
    public Object modifyRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        
        // 在这里修改请求对象
        // 例如,更改参数值
        request.setParameter("yourParam", "newValue");
        
        // 使用修改后的请求继续
        Object result = joinPoint.proceed();
        
        // 如果需要,您还可以修改控制器方法返回的结果
        
        return result;
    }
}
英文:

I did the same using @Arround annotation. Here is the doc 6.2.4.5. Around advice (You need to search @around after going to the link). You can modify both the request and response.

There is also @Before and @After advice you can use if required. If you only need to access the object BEFORE controller is invoked, @Before should be enough.

@Aspect
@Component
public class RequestModifierAspect {
    
    @Around(&quot;execution(* com.example.YourController.methodName(..))&quot;)
    public Object modifyRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        
        // Modify the request object here
        // For example, change a parameter value
        request.setParameter(&quot;yourParam&quot;, &quot;newValue&quot;);
        
        // Proceed with the modified request
        Object result = joinPoint.proceed();
        
        // You can also modify the result returned by the controller method if needed
        
        return result;
    }
}

huangapple
  • 本文由 发表于 2023年5月14日 17:14:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76246694.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定