概念
一般的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/info
文笔不好,可能有的地方没有把逻辑说清楚,重点看公共的HttpServlet类和子类的完整代码,看懂了就明白了。