造一个方形轮子文章目录:造一个方形的轮子
01、添加DispatcherServlet
接上一篇《造一个方形的轮子6--Controller支持(上)》
接下来添加处理HTTP请求最核心的类DispatcherServlet,JAVA里提供的最原始的支持WEB的标准就是Servlet规范,类似Tomcat、Jetty都实现了Servlet规范,所以添加一个DispatcherServlet类配置到Tomcat容器中,接管所以路径的请求,在统一处理,就可以实现我们的目的,整理一下DispatcherServlet类的处理流程:
1、获取HTTP请求类型、ContextPath及RequestURI
2、使用
HTTP请求类型:请求路径
到Beans容器中获取对应的ControllerObject对象3、如果没有对应的方法映射则返回404
4、有对应的方法,则根据参数列表从request中获取对应的参数
5、使用反射方法执行对应的方法并获取返回结果
6、如果返回结果是String类型直接返回,其它类型使用JSON序列化后输出
以下是DispatcherServlet.java代码:
package com.jisuye.core;
// import ...
/**
* 统一请求Servlet处理
* @author ixx
* @date 2019-07-14
*/
public class DispatcherServlet extends HttpServlet {
private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class);
private BeansMap beansMap = new BeansMap();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解析url
String contextPath = req.getContextPath();
String httpMethod = req.getMethod();
String uri = req.getRequestURI();
// 匹配到对应的controller
String controllerKey = httpMethod.toLowerCase()+":"+uri.replace(contextPath, "");
ControllerObject controllerObject = beansMap.getController(controllerKey);
// 如果没有匹配,返回404
if(controllerObject == null){
resp.sendError(404);
} else {
// 执行对应方法
Object obj = controllerObject.invoke(req);
// 处理返回结果
String json;
if (obj instanceof String) {
json = (String) obj;
} else {
json = JSON.toJSONString(obj);
resp.setHeader("content-type", "application/json;charset=UTF-8");
}
log.info("http request path:" + controllerKey);
log.info("exec method :" + controllerObject.getMethod().getName());
log.info("response:" + json);
resp.getWriter().print(json);
}
}
}
对应的修改ControllerObject类,添加如下方法:
/**
* controller对象
* @author ixx
* @date 2019-07-14
*/
public class ControllerObject {
......
/**
* 反射执行controller方法
* @param req
* @return
*/
public Object invoke(HttpServletRequest req){
Object[] os = new Object[params.length];
int i = 0;
for (SquareParam param : params) {
// 如果是String类型则当然参数名从req中取值 否则 当做类 去反射生成
if(param.isParam()){
os[i++] = toBasicDataType(req.getParameter(param.getParamName()), param.getClazz());
} else {
String body = getBody(req);
Object tmp = JSON.toJavaObject(JSONObject.parseObject(body), param.getClazz());
os[i++] = tmp;
}
}
try {
Object o = this.getMethod().invoke(this.getObject(), os);
return o;
} catch (Exception e) {
log.error("Controller method.invoke() is error!", e);
throw new SquareException("Controller method.invoke() is error!", e);
}
}
private Object toBasicDataType(Object obj, Class clazz){
if(obj == null || clazz == null){
return obj;
}
switch (clazz.getName()){
case "int":
case "java.lang.Integer" : obj = Integer.parseInt(obj.toString()); break;
case "long":
case "java.lang.Long" : obj = Long.parseLong(obj.toString()); break;
case "double":
case "java.lang.Double" : obj = Double.parseDouble(obj.toString()); break;
case "float":
case "java.lang.Float" : obj = Float.parseFloat(obj.toString()); break;
case "boolean":
case "java.lang.Boolean" : obj = Boolean.parseBoolean(obj.toString()); break;
case "char":
case "java.lang.Character" : obj = obj.toString().charAt(0); break;
case "byte":
case "java.lang.Byte" : obj = Byte.parseByte(obj.toString()); break;
default: break;
}
return obj;
}
public String getBody(HttpServletRequest req){
String body = "";
try {
BufferedReader br = req.getReader();
String tmp;
while ((tmp = br.readLine()) != null){
body += tmp;
}
} catch (IOException e) {
log.error("getBody data error!", e);
throw new SquareException("Controller parameter getBody data error!", e);
}
return body;
}
......
}
02、配置DispatcherServlet
到目前为止基础的代码基本写完了,现在把DispatcherServlet配置到Tomcat中,修改SquareApplication.run方法:
public class SquareApplication {
// ......
public static void run(Class clzz, String[] args) {
......
tomcat = new Tomcat();
// 设置Tomcat工作目录
tomcat.setBaseDir(classesPathUtil.getProjectPath() + "/Tomcat");
tomcat.setPort(TOMCAT_PORT);
Context context = tomcat.addWebapp(CONTEXT_PATH, classesPathUtil.getPublicPath());
// 添加DsipatcherServlet
Wrapper wrapper = Tomcat.addServlet(context, "DispatcherServlet", new DispatcherServlet());
wrapper.addMapping("/");
......
tomcat.start();
......
}
}
03、添加测试类
现在添加测试类,测试一下Controller。
这里添加一个TestController,有三个方法分别测试Get、Post、Delete方法(Put方法跟Post相同就不做单独测试),参数覆盖@RequestParam和@RequestBody 两种,再结合JdbcTemplate测试一下数据库操作。
TestController.java:
package com.jisuye.service;
// import ...
@Controller("/test")
public class TestController {
@Resource
private JdbcTemplate jdbcTemplate;
@GetMapping("/hello")
public List<AbcEntity> test(@RequestParam("name") String name, @RequestParam("a") String age){
List<AbcEntity> list = jdbcTemplate.select("select * from abc where name=?", AbcEntity.class, name);
return list;
}
@DeleteMapping
public String testDel(@RequestParam("id") int id){
int i = jdbcTemplate.delete("delete from abc where id=?", id);
return "delete id : "+id+" is success";
}
@PostMapping("/post")
public ResponseVo testPost(@RequestParam("id") int id, @RequestBody TestVo vo){
ResponseVo responseVo = new ResponseVo();
responseVo.setResId(id*10);
responseVo.setResAge(vo.getAge()*2);
responseVo.setResName(vo.getName());
return responseVo;
}
}
TestVo.java:
package com.jisuye.service;
public class TestVo {
private String name;
private int age;
// getter and setter ...
}
ResponseVo.java:
package com.jisuye.service;
public class ResponseVo {
private int resId;
private String resName;
private int resAge;
// getter and setter ...
}
04、测试结果
启动程序,使用Postman测试。
测试Get请求
GET http://localhost:8888/abc/test/hello?name=ixx&a=23
响应结果:
[
{
"id": 2,
"name": "ixx"
},
{
"id": 3,
"name": "ixx"
},
{
"id": 4,
"name": "ixx"
}
]
测试Post请求
POST http://localhost:8888/abc/test/post?id=3
body:
{
"name":"ixx",
"age":18
}
响应结果:
{
"resAge": 36,
"resId": 30,
"resName": "ixx"
}
测试Delete请求
DELETE http://localhost:8888/abc/test?id=2
响应结果:
delete id : 2 is success
测试404请求
测试一下如果路径不存在的情况:
GET http://localhost:8888/abc/test/hello4
响应结果:
<!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">h1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} h2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} h3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} body {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} b {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} p {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;} a {color:black;} a.name {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/9.0.17</h3></body></html>
可以看到,返回了404的错误页面。
05、遗留问题
Controller最最基本的功能实现了,但还有很多问题没有处理,比如程序异常的处理(返回500)、form表单参数、文件上传,参数默认值等,下一篇有可能挑一部分解决一下吧...
本篇代码地址: https://github.com/iuv/square/tree/square6
本文作者: ixx
本文链接: http://jianpage.com/2019/07/17/square7
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!