总思路
项目在一些特殊的情况下可能会将一个请求转发给另一个请求去处理,有可能是业务系统直接互相调用。也有可能第一个请求只做了转发不做实际的处理,第二个请求才去做实际的处理。也有可能两个i请求的处理方式都是由第二种给出的等等。
这里我的场景是做请求转发,实际处理依旧是第二个请求去处理。 这里通过资料查询以及实践给出三种请求转发的方式和案例:
一、HandlerInterceptorAdapter 方式(参考资料)
为了准确定位一些Controller的方法,我自定义了注解去判断是否需要执行转发逻辑,或者你也可以直接通过请求路径判断似乎做转发逻辑,示例如下: 我的注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NeedHandle {
}
我的 HandlerInterceptorAdapter 这里只用到了 preHandle 的处理 还有其他方法可以重写
preHandle 为进入实际请求controller 之前的自定义动作
import com.dtdream.dthink.dtalent.dmall.annotation.NeedHandle;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class OpenCheckInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod)handler;
if (handlerMethod.hasMethodAnnotation(NeedHandle.class)){
String requestURI = request.getRequestURI();
String replacePath = requestURI.replace("/open", "");
request.getRequestDispatcher(replacePath).forward(request, response);
}
return true;
}
}
当然 如果为一般的 springMvc 你的这个类需要加入到对应xml 中或者直接使用 @Component 注解 将拦截器注入完成 使用注解时 如下:
@Component
public class OpenCheckInterceptor extends HandlerInterceptorAdapter {
..........
}
xml 方式如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
....................
.................... 其他
....................
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.aurora.interceptor.HttpInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.aurora.interceptor.OpenCheckInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
该方法实际在我的项目中前半段是生效的,但是转发时出现了问题,可能是由于项目框架较老而且内部对请求做了很多其他的特殊处理,实际我修改了部分代码如下 如果你也出现了问题可以参考我的其他思路
这里我替换了 String requestURI = request.getRequestURI(); 为 String requestURI = request.getRequestURL().toString();
实际测验后才进入了我想要进入的controller 中
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod)handler;
if (handlerMethod.hasMethodAnnotation(NeedHandle.class)){
String requestURI = request.getRequestURL().toString();
String replacePath = requestURI.replace("/open", "");
request.getRequestDispatcher(replacePath).forward(request, response);
}
return true;
}
二、Filter
Filte 过滤器的修改方式与上方第一个方法差不多 这里还有其他可重写方法,这里只用到了 doFilter 示例如下: 使用注解的方式:
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "myFilter", urlPatterns = {"/*"})
@Component
public class OpenCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if ((servletRequest instanceof HttpServletRequest) && (servletResponse instanceof HttpServletResponse)){
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse; String requestURI = request.getRequestURI();
if (requestURI.contains("/open/test")){
String replacePath = requestURI.replace("/open", "");
request.getRequestDispatcher(replacePath).forward(request, response);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
如果不使用注解的方式 则需要找 web.xml 中添加对应的 filter 类似如下: web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
.............
............. 其他
<filter>
<filter-name>openFilter</filter-name>
<filter-class>com.dtdream.dthink.dtalent.dmall.filter.ReceiveManagerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>openFilter</filter-name>
<url-pattern>/api/v1/test/*</url-pattern>
</filter-mapping>
</web-app>
但是在这里我遇到了和上面一样的问题,依旧失败没能进入目标 controller,所以采用了同样的修改方式 将 String requestURI = request.getRequestURI(); 替换为 String requestURI = request.getRequestURL().toString();
如果遇到可以参考这样的方式;
三、ModelAndView
这个需要是 springframework(spring 框架) 才能使用 方式类似,但ModelAndView 中 View 指定了访问的地址或者资源路径,跳转路径,Model 即携带的参数 使用案例: 这里我重新定义了一个 controller
@RequestMapping("/open")
@RestController
public class OpenApiPathController {
private static final String REDIRECT_ ="redirect:";
@GetMapping("/test/count")
public ModelAndView messageCount(HttpServletRequest request, HttpServletResponse response){
String replace = request.getRequestURL().toString().replace("/open/test/count", "/test/count");
Map<String, String[]> parameterMap = request.getParameterMap();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(REDIRECT_ + replace);
modelAndView.addAllObjects(parameterMap);
return modelAndView;
}
这里我使用 request.getRequestURL() 才最终成功,但也可以试试 request.getRequestURI() 搜寻的资料中大部分用的都是URI 可以成功,但我只有 URL时才成功。
redirect: + 请求 为固定写法 冒号( : )不可以省略 一般来说 redirect: 后默认携带/ 如果你的有问题可以携带 / 再次尝试一次 转发时可以使用 forward:
总结
拦截请求并转发请求可以使用 HandlerInterceptorAdapter,Filter,ModelAndView 三种方式或者其他 如果 request 获取的 requestURI 不能成功则尝试使用 requestURL 。转发请求 不是 forword(转发)就是redirect(重定向)
|