0
点赞
收藏
分享

微信扫一扫

通过搭建demo-spring-framework-v2,初识Spring框架


文章目录

  • ​​1.demo-spring-framework-v1 存在的问题​​
  • ​​1.1.不能像spring那样支持url的正则匹配​​
  • ​​1.2.参数数据类型转换问题​​
  • ​​2.demo-spring-framework-v2 改造​​
  • ​​2.1.首先,由于我们主要是为解决正则匹配的问题,所以前面四步不做调整​​
  • ​​2.2.支持正则匹配 initHandlerMapping方法的改造​​
  • ​​2.2.1.原来的initHandlerMapping方法​​
  • ​​2.2.1.改造后initHandlerMapping方法​​
  • ​​2.2.3.改造前后initHandlerMapping方法对比​​
  • ​​2.2.4.将handlingMappings由map类型改造为List类型(具体细节保存到Handler对象中)​​
  • ​​2.2.5.既然初始化的映射关系改了,那么请求的时候匹配要进行改造:doDispatcher​​
  • ​​2.2.6.初步测试[HTTP Status 500 - For input string: "[10]"​​
  • ​​2.2.6.1.测试地址:demo/add?a=10&b=5​​
  • ​​2.2.6.2.原因:参数类型的值为数组类型​​
  • ​​2.2.7.优化参数类型数组问题:​​

1.demo-spring-framework-v1 存在的问题

1.1.不能像spring那样支持url的正则匹配

1.2.参数数据类型转换问题

2.demo-spring-framework-v2 改造

@Override
public void init(ServletConfig config) throws ServletException {

//使用模板模式
//1.加载配置文件
this.reloadConfig(config);
//2.扫描所有的类
this.scanner(propertiesConfig.getProperty("scanPackage"));
//3.初始化IOC容器:扫描所有的相关类的实例
this.initIOC();
//4.完善依赖类的依赖注入
this.doAutowired();
//5.初始化调用URL与调用类和方法的关联关系
this.initHandlerMapping();
}

我们在Controller类中定义一个一个新的方法

@MyRequestMapping("/add")
public void add(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
@MyRequestParam("a") Integer a,@MyRequestParam("b") Integer b){
Integer result=iDemoService.add(a, b);
try {
httpServletResponse.getWriter().write("a+b = "+a+"+"+b+" = "+result.toString());
} catch (IOException e) {
e.printStackTrace();
}
}

2.1.首先,由于我们主要是为解决正则匹配的问题,所以前面四步不做调整

//使用模板模式
//1.加载配置文件
this.reloadConfig(config);
//2.扫描所有的类
this.scanner(propertiesConfig.getProperty("scanPackage"));
//3.初始化IOC容器:扫描所有的相关类的实例
this.initIOC();
//4.完善依赖类的依赖注入
this.doAutowired();

2.2.支持正则匹配 initHandlerMapping方法的改造

2.2.1.原来的initHandlerMapping方法

private void initHandlerMapping() {

if (iocMap.isEmpty()){
return;
}
for (Map.Entry entry:iocMap.entrySet()) {
Class<?> clazz= entry.getValue().getClass();
if (!clazz.isAnnotationPresent(MyController.class)){
continue;
}
String baseUrl="";
if (clazz.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping myRequestMapping=clazz.getAnnotation(MyRequestMapping.class);
baseUrl=myRequestMapping.value();
}

//默认获取所有的public方法
Method[] methods=clazz.getMethods();
for (Method method:methods){
if (!method.isAnnotationPresent(MyRequestMapping.class)){
continue;
}

MyRequestMapping myRequestMapping=method.getAnnotation(MyRequestMapping.class);
//如果有连续的//,替换成一个/
String url=(baseUrl+"/"+myRequestMapping.value()).replaceAll("/+","/");

handlingMappings.put(url,method);
}
}
}

2.2.1.改造后initHandlerMapping方法

private void initHandlerMapping() {

if (iocMap.isEmpty()){
return;
}
for (Map.Entry entry:iocMap.entrySet()) {
Class<?> clazz= entry.getValue().getClass();
if (!clazz.isAnnotationPresent(MyController.class)){
continue;
}
String baseUrl="";
if (clazz.isAnnotationPresent(MyRequestMapping.class)){
MyRequestMapping myRequestMapping=clazz.getAnnotation(MyRequestMapping.class);
baseUrl=myRequestMapping.value();
}

//默认获取所有的public方法
Method[] methods=clazz.getMethods();
for (Method method:methods){
if (!method.isAnnotationPresent(MyRequestMapping.class)){
continue;
}

MyRequestMapping myRequestMapping=method.getAnnotation(MyRequestMapping.class);
//如果有连续的//,替换成一个/
String url=(baseUrl+"/"+myRequestMapping.value()).replaceAll("/+","/");

Pattern pattern=Pattern.compile(url);
handlingMappings.add(new Handler(entry.getValue(),method,pattern));

System.out.println("handlingMappings + =" +url+",method = " +method);
}
}
}

2.2.3.改造前后initHandlerMapping方法对比

通过搭建demo-spring-framework-v2,初识Spring框架_正则匹配

2.2.4.将handlingMappings由map类型改造为List类型(具体细节保存到Handler对象中)

通过搭建demo-spring-framework-v2,初识Spring框架_spring_02

class Handler{

protected Object controller; //保存方法对应的类实例
protected Method method; //保存映射的方法
protected Pattern pattern; //保存路径的正则匹配规则
protected Map<String,Integer> paramIndexMapping; //保存参数顺序

public Handler(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
this.paramIndexMapping = this.setParamIndexMapping(method);
}


private Map<String,Integer> setParamIndexMapping(Method method){

paramIndexMapping=new HashMap<String,Integer>();

/**
* 二维数组主要是基于每一个参数都有可能多个注解如 name字段两个注解,当然也可以三个,四个等等
* 如:
* public void query(HttpServletRequest httpServletRequest,
* HttpServletResponse httpServletResponse,
* @MyRequestParam("name") @RequestParam("xingming") String name)
*/
Annotation[][] annotations=method.getParameterAnnotations();
for (int i=0;i<annotations.length;i++){
/**
* 再次循环每个字段的注解(上面说了,每一个字段的注解是有可能多个的)
*/
for (Annotation annotation:annotations[i]){
if (annotation instanceof MyRequestParam){
String myRequestParamValue=((MyRequestParam) annotation).value();
if (!"".equals(myRequestParamValue)){
paramIndexMapping.put(myRequestParamValue,i);
}
}
}
}

/**
* 获取方法的所有的参数列表
*/
Class<?>[] parameterTypes=method.getParameterTypes();
for (int i=0;i<parameterTypes.length;i++){
Class<?> parameterType=parameterTypes[i];
if (parameterType ==HttpServletRequest.class||parameterType==HttpServletResponse.class){
paramIndexMapping.put(parameterType.getName(),i);
}
}
return paramIndexMapping;
}

}

通过搭建demo-spring-framework-v2,初识Spring框架_java_03

2.2.5.既然初始化的映射关系改了,那么请求的时候匹配要进行改造:doDispatcher

private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException {

System.out.println("请求进来了。。。。。");
String url=req.getRequestURI();
System.out.println("Current URL = " +req.getRequestURL());
System.out.println("Current URI = " +url);
String contextPath=req.getContextPath();
url=url.replaceAll(contextPath,"").replaceAll("/+","/");

Handler handlerResult=null;
for (Handler handler:handlingMappings){
Matcher matcher=handler.pattern.matcher(url);
if (!matcher.matches()){
continue;
}
handlerResult=handler;
}
if (handlerResult==null){
resp.getWriter().write("404 Url Not Found");
return;
}


/**
* 这里大家注意下,我们的URL参数中,可以同一个key可以赋值两个,比如
* http://localhost:8080/demo_spring_framework_v2_war/demo/add?a=10&b=5&b=6
* 这里的话,b对应的就是一个数组String[]---->[5,6]
*/
Map<String,String[]> params=req.getParameterMap();
Class<?>[] paramterTypes=handlerResult.method.getParameterTypes();
Object[] paramValues=new Object[paramterTypes.length];

for (Map.Entry<String,String[]> param:params.entrySet()){
//为了防止URL中有可能有空格,我们将值去除一下空格,也可以不做处理
String value=Arrays.toString(param.getValue());

if (!handlerResult.paramIndexMapping.containsKey(param.getKey())){
continue;
}
int index=handlerResult.paramIndexMapping.get(param.getKey());
// paramValues[index]=value;
/**
* 这里所有值的类型上面显示的都是String类型,但是在具体的方法定义时,有可能不是的
* 所以我们需要根据方法中的参数类型,对String类型做一下转换
* 这样下面进行方法的反射调用的时候,能够找到对应的类和方法
*/
paramValues[index]= StringUtils.convert(value,paramterTypes[index]);
}

/*
Map<String,String[]> params=req.getParameterMap();
因为我们通过上面的方法获取参数列表的时候,默认是没有
*/
int reqIndex= handlerResult.paramIndexMapping.get(HttpServletRequest.class.getName());
paramValues[reqIndex]=req;
int resIndex= handlerResult.paramIndexMapping.get(HttpServletResponse.class.getName());
paramValues[resIndex]=resp;

try {
handlerResult.method.invoke(handlerResult.controller,paramValues);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}

2.2.6.初步测试[HTTP Status 500 - For input string: “[10]”

2.2.6.1.测试地址:demo/add?a=10&b=5

​​http://localhost:8080/demo_spring_framework_v2_war/demo/add?a=10&b=5​​

HTTP Status 500 - For input string: "[10]"
type Exception report

message For input string: "[10]"

description The server encountered an internal error that prevented it from fulfilling this request.

exception

java.lang.NumberFormatException: For input string: "[10]"
java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
java.lang.Integer.parseInt(Integer.java:580)
java.lang.Integer.parseInt(Integer.java:615)
com.gaoxinfu.demo.spring.framework.v2.util.StringUtils.convert(StringUtils.java:12)
com.gaoxinfu.demo.spring.framework.v2.servlet.MyDispatcherServlet.doDispatcher(MyDispatcherServlet.java:100)
com.gaoxinfu.demo.spring.framework.v2.servlet.MyDispatcherServlet.doPost(MyDispatcherServlet.java:51)
com.gaoxinfu.demo.spring.framework.v2.servlet.MyDispatcherServlet.doGet(MyDispatcherServlet.java:46)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.55 logs.

Apache Tomcat/7.0.55

2.2.6.2.原因:参数类型的值为数组类型

通过搭建demo-spring-framework-v2,初识Spring框架_spring_04

2.2.7.优化参数类型数组问题:

private void doDispatcher(HttpServletRequest req, HttpServletResponse resp) throws IOException {

System.out.println("请求进来了。。。。。");
String url=req.getRequestURI();
System.out.println("Current URL = " +req.getRequestURL());
System.out.println("Current URI = " +url);
String contextPath=req.getContextPath();
url=url.replaceAll(contextPath,"").replaceAll("/+","/");

Handler handlerResult=null;
for (Handler handler:handlingMappings){
Matcher matcher=handler.pattern.matcher(url);
if (!matcher.matches()){
continue;
}
handlerResult=handler;
}
if (handlerResult==null){
resp.getWriter().write("404 Url Not Found");
return;
}


/**
* 这里大家注意下,我们的URL参数中,可以同一个key可以赋值两个,比如
* http://localhost:8080/demo_spring_framework_v2_war/demo/add?a=10&b=5&b=6
* 这里的话,b对应的就是一个数组String[]---->[5,6]
*/
Map<String,String[]> params=req.getParameterMap();
Class<?>[] paramterTypes=handlerResult.method.getParameterTypes();
Object[] paramValues=new Object[paramterTypes.length];

for (Map.Entry<String,String[]> param:params.entrySet()){
//为了防止URL中有可能有空格,我们将值去除一下空格,也可以不做处理
// String value=Arrays.toString(param.getValue());
String value=Arrays.toString(param.getValue()).replaceAll("\\[|\\]","").replaceAll("\\s","");

if (!handlerResult.paramIndexMapping.containsKey(param.getKey())){
continue;
}
int index=handlerResult.paramIndexMapping.get(param.getKey());
// paramValues[index]=value;
/**
* 这里所有值的类型上面显示的都是String类型,但是在具体的方法定义时,有可能不是的
* 所以我们需要根据方法中的参数类型,对String类型做一下转换
* 这样下面进行方法的反射调用的时候,能够找到对应的类和方法
*/
paramValues[index]= StringUtils.convert(value,paramterTypes[index]);
}

/*
Map<String,String[]> params=req.getParameterMap();
因为我们通过上面的方法获取参数列表的时候,默认是没有
*/
int reqIndex= handlerResult.paramIndexMapping.get(HttpServletRequest.class.getName());
paramValues[reqIndex]=req;
int resIndex= handlerResult.paramIndexMapping.get(HttpServletResponse.class.getName());
paramValues[resIndex]=resp;

try {
handlerResult.method.invoke(handlerResult.controller,paramValues);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}

验证

通过搭建demo-spring-framework-v2,初识Spring框架_正则匹配_05


举报

相关推荐

0 条评论