javaweb 重构servlet思想:

每一个请求都需要一个servlet太麻烦,也太累赘,,想想可不可以把请求放在一个servlet里面处理,,让具体的不同方法处理不同的请求思想,,可不可以。。

问题:

  1. 如何让方法有处理请求的能力
  2. 如何判断一次请求被哪一个方法所处理
  3. 如何实现这样的操作呢。。。想到:所有的servlet实际上都是去调用了service方法。。那可以吧service方法共性提出来。。在里面实现呢。。

思路《构建一个baseServlet:》利用注解接收请求地址映射,利用反射在service实现。。

第一步:构建一个baseServlet,,去继承HTTPServlet

public class BaseServlet extends HttpServlet {。。。。。}

第二步:去重写service方法:

 @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) {。。。。。。。}

第三步:如何去拿到继承自baseServlet类的处理请求的方法:。。。。

在这之前,先写一个类实现baseServlet。。写一个查询全部的方法》利用自定义注解里面写请求路径:

public class ProductServlet extends BaseServlet {
 @Path("/detail")
    public String findById() {。。。。}
}

注解自定义创建一个:

@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(ElementType.METHOD)//注解标记在方法上。
public @interface Path {
    String value();
}

现在回到baseservlet,如何获取注解里面的内容和方法信息。。想到的技术,,反射。。

获取URI:解析具体的请求:这想到request对象就可以获取得到。。。。

 String uri = req.getRequestURI();

获取子类的方法:那就通过class对象的反射技术了。。

如何获取具体的子类对象呢,this关键字。。代表执行的本对象本身。。this.getClass();不就获取到它的字节码对象么。。。

 Method[] methods = this.getClass().getDeclaredMethods();

方法是一个数组,遍历就完事,遍历完该干嘛。。。那肯定是获取方法上的注解里面的值:

 for (Method method : methods) {
            String path = method.getAnnotation(Path.class).value();     
 }

获取到注解里面的值了,接下来判断一次请求是否满足哪一个注解里面的路径值呢。。找到满足的得处理方法,把该方法返回出去,service获取到该方法,做出业务处理。

if (uri.contains(path)) {
                return method;
}

该业务完整:代码

复制代码
 private Method findMethod(HttpServletRequest req) {
        String uri = req.getRequestURI();
        Method[] methods = this.getClass().getDeclaredMethods();
        for (Method method : methods) {
            String path = method.getAnnotation(Path.class).value();
            if (uri.contains(path)) {
                return method;
            }
        }
        return null;
    }
复制代码

找到了处理请求的方法,,,在service方法里面,接下来判断这个方法是不是null;如果是null那就返回404等提示信息。

复制代码
// 根据URI来找出对应的方法
            Method method = findMethod(request);
            // 如果没有找到就返回404
            if (method == null) {
                response.setStatus(404);
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write("<h3 style='margin-top: 200px;text-align: center; color: green'>没有匹配的方法</h3>");
                return;
            }
复制代码

如果找到了该方法,该方法并且存在。。。那么就交给该方法处理》该方法处理请求与响应。就需要至少两个对象,

HttpServletRequest request;
HttpServletResponse response;
所以在baseServlet类里面想想如何把这两个对象穿透给子类使用呢。利用成员变量:作用域提升至:protected及其以上,也可以把这两个对象当做传递参数给子类。。。。
这里选择成员变量作用域方式;具体的对象是service方法里面的两个对象,刚好是,所以把这两个赋值给baseServlet定义的成员变量中:
复制代码
 // 通过"内置对象"的思维来创建的两个可以在子类中直接使用的成员变量
    protected HttpServletRequest request;
    protected HttpServletResponse response;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) {
        // 每一次请求过来时都会被赋值
        this.request = req;
        this.response = resp;
。。。。。。。。。。。。。。
复制代码

好了:想想方法怎么处理响应呢:方法要么没返回值要么有返回值。。。。这个返回值拿来还有什么用、??

想到一点:如果返回字符串可不可以重定向或者转发到对应的jsp页面中呢。。。好主意。。。。

那么先调用方法,得到返回值的结果。。。。。。。反射   : invok(),然后比较返回的值是什么类型

// 调用对应的方法
            Object result = method.invoke(this);
            if (result instanceof String) {
                // 如果是字符串就跳转页面
                result = (String) result;
                request.getRequestDispatcher("/jsp/" + result + ".jsp").forward(req, resp);
            } 

那么要是返回的东西不是字符串类型。。不是字符串那就是基本数据类型。。。或者复杂的集合类型。。。。

基本数据类型没撒用呀。。。那就复杂数据类型,集合。。是用于封装数据的,那就转成json传递回去。。。

利用jackson第三方工具:

         // 如果是对象那么就转成json字符串响应给前端
                // 被转化的对象一定要有getter与setter
                ObjectMapper objectMapper = new ObjectMapper();
                response.setContentType("application/json;charset=utf-8");
                objectMapper.writeValue(response.getWriter(), result);

公共功能抽取完成了,,交给具体的方法执行具体的业务逻辑处理请求与响应啦:

比如根据id查询:

复制代码
 @Path("/detail")
    public String findById() {
        // 1 接受参数
        String id = request.getParameter("id");
        // 2 查询数据
        ProductService productService = new ProductService();
        Product product = productService.findById(id);
        // 3 存储数据
        request.setAttribute("product", product);
        return "detail";
    }
复制代码

解析:

依赖service处理业务,调用dao层把具体的功能执行到,得到结果集,,交给requset域对象传递数据,,利用baseservlet父类的业务处理,携带数据肯定是转发,那么方法返回值为string就可以完成,string具体的返回值,就是转发的具体的jsp的文件的名字。。。重构的baseservlet接收到处理方法的返回值是string,那就回执行转发的路径拼接,完成功能。。。。。后期jsp目标网页只需要利用内置request对象获取属性即可。。。。。

比如返回一个集合:

复制代码
 **/
public class CategoryServlet extends BaseServlet {

    // /category/list
    @Path("list")
    public List<Category> findAll() {
        return new CategoryService().findAll();
    }
}
复制代码

baseServlet接收到方法是返回的集合,那就转成json格式返回回去。。。。最常见的ajax。。回调。。。就可以获取json字符串。。

 

 

写完了这次的思想,这怎么越来越像是springmvc的模样,@COntroller不就是标记这是一个servlet处理的类么,@XXMapping不就是接受的请求路径么,,方法不就是处理具体的请求与响应的么。。。。框架的底层就是对复杂的代码的重构,抽取,封装,优化以及简单易用的实现,作为接口来被工作人员调用方法以比较优化方式实现具体的业务功能。。。。本质还是这些技术,推断出框架主要核心技术是反射和注解的java基础知识的理解。。。。。构建出来的。。。。。

 

 

当然这远远不够,,,还需要日积月累。。。。。。

 

posted on   白嫖老郭  阅读(154)  评论(0编辑  收藏  举报

编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示