HttpServlet结合Java反射实现调用方法

概念

一般的servlet编程中,一个类继承HttpServlet,重写doGet,doPost方法,然后去web.xml配置servlet或者注解配置,就可以使用了。
但是这样有一个问题,一个API就对应一个类,最后造成类很多。用过springMVC的应该知道,一个Controller中,一般在类上配上一个@RequestMapping标识,比如:

@RequestMapping("/api/order")
public class OrderController

然后在方法上配置@RequestMapping,这样类中配置了@RequestMapping注解的方法就都可以当做一个API来使用

// API /api/order/info
@RequestMapping("/info")
public String info(Long id){
	// do something ......
}
// API /api/order/save
@RequestMapping("/save")
public String save(@RequestBody OrderEntity order){
	// do something ......
}
// API /api/order/list
@RequestMapping("/list")
public String list(@RequestParam Map<String, Object> params){
	// do something ......
}

接下来,我用servlet来简单实现springMVC这种模式

定义一个公共的HttpServlet类

这个公共类的目的就是,通过请求参数中的RequestURI,解析出要请求的方法名,然后通过反射调用。
HttpServletRequest.getRequestURI()会获得完整的请求,比如上面的例子中,会得到

/api/order/info
/api/order/save
/api/order/list

那么我们要做的就是把"/api/order/"给去掉,就得到要访问的方法了。
所以,我们给公共的HttpServlet类加了一个抽象方法。这个继承的子类实现该方法,把需要替换掉的公共的requestURI返回上来就可以了。

/**
     * 需要将requestURI替换调用的字符串,替换掉后得到真正的要查询的方法
     * 每个子类需要覆盖掉该方法,改为自己UrlPattren的值
     */
    public abstract String getUriReplace();

然后公共的HttpServlet类就可以替换得到要调用的方法名,然后反射调用

        /**
         * 根据子类实现的getUriReplace()方法,替换掉URL标识,找到真正的方法名
         */
        String requestURI = req.getRequestURI();
        String methodName=requestURI.replace(getUriReplace(),"");

完整的公共HttpServlet类代码如下

/**
 * @Author lyc
 * @Date 2021/06/09
 * @Des 公共的servlet类,通过Java的反射机制,调用请求方法
 */
public abstract class MyPublicHttpServlet extends HttpServlet {

    /**
     * 需要将requestURI替换调用的字符串,替换掉后得到真正的要查询的方法
     * 每个子类需要覆盖掉该方法,改为自己UrlPattren的值
     */
    public abstract String getUriReplace();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         * 解决响应乱码
         */
        resp.setContentType("text/html;charset=UTF-8");

        /**
         * 根据子类实现的getUriReplace()方法,替换掉URL标识,找到真正的方法名
         */
        String requestURI = req.getRequestURI();
        String methodName=requestURI.replace(getUriReplace(),"");

        try {
            Method method = getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this,req,resp);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
            /**
             * 反射调用方法出错
             * TODO 抛出异常,全局异常处理器来处理异常
             */
            resp.getWriter().write("亲,没有你要的服务/(ㄒoㄒ)/~~");
        }
    }
}

定义一个公共的HttpServlet类的子类

这个子类必须实现getUriReplace()方法,告诉父类要替换掉的Uri。然后每个方法都是一个API了
完整代码如下:

@WebServlet("/hello/*")
public class HelloController extends MyPublicHttpServlet {
    /**
     * url标识,需要替换到这个字符串
     * 替换掉后的字符串,就是真正要执行的方法
     */
    String uriReplace="/hello/";

    @Override
    public String getUriReplace() {
        return this.uriReplace;
    }

    /**
     * @API /hello/sayHello
     * @param req
     * @param resp
     */
    public void sayHello(HttpServletRequest req,HttpServletResponse resp){
        try {
            resp.getWriter().write("Hi,这里是学生信息管理系统,系统虽然还不健全,但是在努力开发中哦O(∩_∩)O");
        } catch (IOException e) {
            e.printStackTrace();
            /**
             * TODO 抛出异常,全局异常处理器统一处理
             */
        }
    }

    /**
     * @API /hello/info
     * @param req
     * @param resp
     */
    public void info(HttpServletRequest req,HttpServletResponse resp){
        Date date = new Date();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("时间:"+date+" <br/>");
        stringBuilder.append("服务名:学生信息管理系统 <br/>");
        stringBuilder.append("开发者:lyc <br/>");
        try {
            resp.getWriter().write(new String(stringBuilder));
        } catch (IOException e) {
            e.printStackTrace();
            /**
             * TODO 抛出异常,全局异常处理器统一处理
             */
        }
    }
}

测试

/hello/sayHello
/hello/sayHello
/hello/info
/hello/info
文笔不好,可能有的地方没有把逻辑说清楚,重点看公共的HttpServlet类和子类的完整代码,看懂了就明白了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值