java requesMapping_注解实现请求URL映射到Java方法

本文介绍如何使用Java的@Controller和@RequestMapping注解将HTTP请求映射到对应的处理方法。首先定义了@Controller和@RequestMapping注解,接着枚举了RequestMethod。接着,通过RequestHandler类存储URL和方法信息,并通过RequestMappingProcessor扫描并解析注解,建立映射关系。最后,通过RequestFilter和AuthenticationFilter过滤并处理请求,DispatchServlet负责分发请求到正确的方法。
摘要由CSDN通过智能技术生成

效果

收到请求并且鉴权后会自动映射请求到方法上来

2bbb693a833a

image.png

实现

1、定义@Controller 注解,标识类需要被扫描

/**

* 标识类需要被扫描

*/

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Controller {

}

2、定义@RequestMapping 注解,标识类需要被扫描

/**

* 映射url到类和方法上

*/

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

public @interface RequestMapping {

//url

String value();

//默认为GET

RequestMethod method() default RequestMethod.DEFAULT;

//是否需要身份验证

boolean auth() default true;

}

3、RequestMethod 用于枚举请求的方法

/**

* 请求方法枚举,只枚举了我们需要的方法

*/

public enum RequestMethod {

GET, POST, DELETE, DEFAULT

}

4、RequestHandler 用于存放url映射到方法的相关信息

/**

* 请求处理者类

*

* @author Jerry

* @date 2019/7/22 11:01

*/

public class RequestHandler {

//映射的路径

public String path;

//方法GET、POST等

public RequestMethod requestMethod;

//类对象

public Class clazz;

//方法对象

public Method method;

//类的实例对象

public Object instance;

//是否需要身份验证

public boolean isAuth;

}

5、RequestMappingProcessor 用于扫描注解

/**

* 注解扫描器

*

* @author Jerry

* @date 2019/7/22 10:51

*/

public class RequestMappingProcessor {

//存放url到RequestHandler的映射

public static HashMap requestMappingMap = new HashMap<>();

/**

* 扫描解析指定包下的@Controller和@RequestMapping注解

*

* 只能扫描class文件,暂未实现扫描jar包

*

* @return 生成的映射表

*/

public static HashMap scanRequestMapping() {

//扫描的包路径

final String pkgPath = "com/zlt/controller";

//用于字符拼接

final String pkgClassPath = pkgPath.replace("/", ".") + ".";

requestMappingMap.clear();

Enumeration enumeration = null;

try {

//获取该包下的class文件

enumeration = Thread.currentThread().getContextClassLoader().getResources(pkgPath);

} catch (IOException e) {

e.printStackTrace();

}

if (enumeration == null) {

System.out.println("扫描失败");

return null;

}

try {

while (enumeration.hasMoreElements()) {

URL url = enumeration.nextElement();

File file = new File(url.getFile());

String[] fileList = file.list();

if (fileList == null) {

System.err.println(file.getAbsolutePath() + "包没有类");

return null;

}

for (String path : fileList) {

Class clazz = Thread.currentThread().getContextClassLoader().loadClass(pkgClassPath + path.substring(0, path.length() - 6));

Controller controller = (Controller) clazz.getAnnotation(Controller.class);

if (controller != null) {

System.out.println(clazz.getName());

RequestMapping parentRequestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);

//类注解上的一级路径

String basePath = null;

RequestMethod baseMethod = null;

if (parentRequestMapping != null) {

//获取类注解上的一级路径

basePath = ensurePath(parentRequestMapping.value());

baseMethod = parentRequestMapping.method();

//忽略类注解上的auth

//baseAuth = parentRequestMapping.auth();

//默认为RequestMethod.GET

if (baseMethod == RequestMethod.DEFAULT) baseMethod = RequestMethod.GET;

}

//生成类的实例对象

Object instance = clazz.newInstance();

System.out.println("扫描到类 " + instance.getClass().getCanonicalName());

for (Method method : clazz.getDeclaredMethods()) {

System.out.println(" " + method.getName() + "()");

RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);

if (requestMapping != null) {//获取到方法上的注解

method.setAccessible(true);

//生成RequestHandler实例

RequestHandler warp = new RequestHandler();

//拼接生成最终的url

warp.path = basePath + ensurePath(requestMapping.value());

//获取方法注解上的RequestMethod

RequestMethod requestMethod = requestMapping.method();

if (requestMethod == RequestMethod.DEFAULT) {

//如果类注解设置了RequestMethod,而方法注解没有设置RequestMethod,则类注解会覆盖方法注解的请求方法

warp.requestMethod = baseMethod != null ? baseMethod : RequestMethod.GET;//默认为GET

} else {//否则使用方法注解上的RequestMethod

warp.requestMethod = requestMethod;

}

warp.method = method;

//默认为true

warp.isAuth = requestMapping.auth();

warp.clazz = clazz;

warp.instance = instance;

//检查参数,这里还可以再检查一下返回值类型什么的

//这里的方法参数类型和个数都是定死了,可以拓展支持不同参数类型和返回类型

if (method.getParameterCount() == 2) {

Class>[] classes = method.getParameterTypes();

if (HttpServletRequest.class == classes[0] &&

HttpServletResponse.class == classes[1]) {

requestMappingMap.put(warp.path, warp);

continue;

}

}

System.err.println(method.getName() + " 参数错误");

}

}

}

}

}

} catch (Exception e) {

e.printStackTrace();

}

if (requestMappingMap != null) {

System.out.println("url映射:");

for (Map.Entry entry : requestMappingMap.entrySet()) {

RequestHandler warp = entry.getValue();

System.out.println(warp.path + " " + warp.requestMethod + " " + warp.clazz.getCanonicalName() + "." + warp.method.getName() + "()");

}

}

return requestMappingMap;

}

/**

* 规范url格式

*

* 标准格式为前有ur开头l“/”而后面没有 如 /user、/user/login等

*/

private static String ensurePath(String path) {

if (!path.startsWith("/")) {

path = "/" + path;

}

if (path.endsWith("/")) {

path = path.substring(0, path.length() - 1);

}

return path;

}

public static HashMap getRequestMappingMap() {

return requestMappingMap;

}

}

6、定义过滤器 RequestFilter ,过滤没有映射的url

/**

* Request过滤类

*

* 通过url、method等过滤未映射的Request

*

* @author Jerry

* @date 2019/7/23 15:57

*/

public class RequestFilter implements Filter {

private HashMap handlerMap = RequestMappingProcessor.getRequestMappingMap();

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

HttpServletRequest request = ((HttpServletRequest) servletRequest);

String fullPath = request.getPathInfo();

RequestHandler handler = handlerMap.get(fullPath);

if (handler != null) {

//把处理者添加到request的attribute中

request.setAttribute(Config.KEY_REQUEST_HANDLER, handler);

filterChain.doFilter(servletRequest, servletResponse);

} else {

//直接就不往下传递请求了,这里可以处理一下,排除一下页面 如druid

System.out.println(request.getRequestURI() + ":没有映射");

}

}

}

7、定义过滤器 AuthenticationFilter ,用于请求鉴权

/**

* 用来过滤未登录的请求

*

* @author Jerry

* @date 2019/7/22 14:16

*/

public class AuthenticationFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

if (servletRequest.getAttribute(Config.KEY_REQUEST_DRUID) != null) {

filterChain.doFilter(servletRequest, servletResponse);

return;

}

RequestHandler handler = (RequestHandler) servletRequest.getAttribute(Config.KEY_REQUEST_HANDLER);

if (handler != null) {

if (handler.isAuth) {//如果需要验证身份

boolean isLogin = false;

try {

//这里始终为false,需要实现鉴权逻辑

isLogin = false;

} catch (Exception e) {

e.printStackTrace();

}

if (isLogin) {//如果鉴权通过

filterChain.doFilter(servletRequest, servletResponse);

} else {

//如果鉴权没通过

}

} else {

filterChain.doFilter(servletRequest, servletResponse);

}

} else {

//处理者为空情况

System.out.println("AuthenticationFilter:" + ((HttpServletRequest) servletRequest).getRequestURI());

}

}

}

8、DispatchServlet 用于执行分发请求到对应方法上

/**

* 负责分发请求的Servlet

*

* 根据配置,分发请求到不同的方法

*

* @author Jerry

* @date 2019/7/20 17:41

*/

public class DispatchServlet extends HttpServlet {

@Override

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

RequestHandler handler = (RequestHandler) request.getAttribute(Config.KEY_REQUEST_HANDLER);

if (handler != null) {

try {

Object data = handler.method.invoke(handler.instance, request, response);

//自己处理返回值

} catch (Exception e) {

response.getWriter().write(ResponseBody.JSON_ERROR_SYSTEM);

e.printStackTrace();

}

} else {

System.err.println(request.getRequestURI());

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值