这几天在家写了一个简陋版的SpringMVC,先把代码贴出来,有兴趣的同学可以看一下。
首先定义了一个简陋的服务器,其实也就是用了ServerSocket写了一个服务端(更详细的点看这里:创建一个简单的web服务器):
public class HttpServer {
public static void main(String[] args) {
await();
}
private static void await() {
ServerSocket serverSocket = null;
try {
ApplicationContext ac = new ApplicationContext(new HttpServletImpl(), "/com/zkn/fullstacktraining/spring/one/spring-config.properties");
ac.init();
boolean shutDown = false;
//创建一个服务端
serverSocket = new ServerSocket(8005, 1, InetAddress.getByName("127.0.0.1"));
//用线程池处理请求
ExecutorService executorService = new ThreadPoolExecutor(10,
10, 0L, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(),
new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build());
while (!shutDown) {
//接收客户端请求
ProcessSocket processSocket = new ProcessSocket(serverSocket.accept());
executorService.execute(processSocket);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
这里用了线程池来处理多个socket连接。
接着我们需要自定义一个Request和Response两个类来处理请求和响应信息。
Request这里存了请求头信息、请求参数信息、请求类型、请求URI等。Request的代码如下:
public class Request {
/**
* 输入流
*/
private InputStream inputStream;
/**
* 头文件信息
*/
private Map<String, String> headerMap = new HashMap<>();
/**
* 参数信息
*/
private Map<String, Object> parameterMap = new HashMap<>();
/**
* 是否被解析过
*/
private boolean isParser = false;
/**
* 请求类型
*/
private String requestMethod;
/**
* 请求URI
*/
private String uri;
public Request(InputStream inputStream) {
this.inputStream = inputStream;
}
/**
* 获取头文件信息
*
* @param key
* @return
*/
public String getHeader(String key) {
if (key == null) {
return null;
}
return headerMap.get(key.toLowerCase());
}
/**
* 获取参数的值
*
* @param key
* @return
*/
public String getParameterValue(String key) {
Object obj = parameterMap.get(key);
if (obj == null)
return null;
if (obj instanceof List) {
if (!((List) obj).isEmpty()) {
return (String) ((List) obj).get(0);
}
return null;
}
return (String) obj;
}
/**
* 获取多个值
*
* @param key
* @return
*/
public List<String> getParameterValues(String key) {
Object obj = parameterMap.get(key);
if (obj == null) {
return null;
}
if (obj instanceof List) {
return (List<String>) obj;
}
return null;
}
/**
* 获取所有的key
*
* @return
*/
public Set<String> getParameterNames() {
return parameterMap.keySet();
}
public String getRequestMethod() {
return requestMethod;
}
/**
* 解析请求
*/
public void parseRequest() {
if (isParser) {
return;
}
isParser = true;
//这里用了BufferedReader 没有考虑性能问题
BufferedReader lineNumberReader = new BufferedReader(new InputStreamReader(inputStream));
try {
//获取请求行 请求行格式 Method URI 协议
String str = lineNumberReader.readLine();
if (str != null) {
String[] strArray = str.split(" ");
requestMethod = strArray[0];
parseUrl(strArray[1]);
}
String headerStr = null;
String[] strArr = null;
//解析头信息
while ((headerStr = lineNumberReader.readLine()) != null) {
if ("".equals(headerStr)) {
break;
}
strArr = headerStr.split(":");
if (strArr.length == 2) {
headerMap.put(strArr[0].toLowerCase(), strArr[1].trim());
}
}
//如果是POST请求
String contentType = null;
if ("POST".equals(requestMethod)) {
//文件上传
if ((contentType = headerMap.get("content-type")) != null && headerMap.get("content-type").startsWith("multipart/form-data")) {
//解析文件上传
parseUploadFile(lineNumberReader, contentType);
} else {
//非文件上传
String postParameter = "";
while ((postParameter = lineNumberReader.readLine()) != null) {
if ("".equals(postParameter)) {
break;
}
wrapperParameterValue(postParameter);
}
}
}
System.out.println(JSON.toJSONString(parameterMap));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("执行完了。。。");
}
private void parseUploadFile(BufferedReader lineNumberReader, String contentType) throws IOException {
String str;//文件上传的分割位 这里只处理单个文件的上传
String boundary = contentType.substring(contentType.indexOf("boundary") + "boundary=".length());
//解析消息体
while ((str = lineNumberReader.readLine()) != null) {
//解析结束的标记
do {
//读取boundary中的内容
//读取Content-Disposition
str = lineNumberReader.readLine();
//说明是文件上传
if (str.indexOf("Content-Disposition:") >= 0 && str.indexOf("filename") > 0) {
str = str.substring("Content-Disposition:".length());
String[] strs = str.split(";");
String fileName = strs[strs.length - 1].replace("\"", "").split("=")[1];
System.out.println("fileName = " + fileName);
//这一行是Content-Type
lineNumberReader.readLine();
//这一行是换行
lineNumberReader.readLine();
//正式去读文件的内容
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("G:\\LearnVideo\\fileLoad" + File.separator + fileName), "UTF-8"));
while (true) {
str = lineNumberReader.readLine();
if (str.startsWith("--" + boundary)) {
break;
}
bw.write(str);
bw.newLine();
}
bw.flush();
} catch (Exception e) {
} finally {
if (bw != null) {
bw.close();
}
}
}
if (str.indexOf("Content-Disposition:") >= 0) {
str = str.substring("Content-Disposition:".length());
String[] strs = str.split(";");
String name = strs[strs.length - 1].replace("\"", "").split("=")[1];
lineNumberReader.readLine();
StringBuilder stringBuilder = new StringBuilder();
while (true) {
str = lineNumberReader.readLine();
if (str.startsWith("--" + boundary)) {
break;
}
stringBuilder.append(str);
}
parameterMap.put(name, stringBuilder.toString());
}
} while (("--" + boundary).equals(str));
//解析结束
if (str.equals("--" + boundary + "--")) {
break;
}
}
}
/**
* 解析URI
*
* @param s
*/
private void parseUrl(String s) {
if ("/".equals(s)) {
uri = "/";
return;
}
String tempStr = s;
/**
* 说明可能带参数
*/
int flag = 0;
if ((flag = tempStr.indexOf("?")) > 0) {
uri = tempStr.substring(0, flag);
if (tempStr.length() > (flag + 1)) {
tempStr = tempStr.substring(flag + 1, tempStr.length());
String[] strArray = tempStr.split("&");
for (String str : strArray) {
wrapperParameterValue(str);
}
}
return;
}
uri = s;
}
/**
* 组装参数值
*
* @param str
*/
private void wrapperParameterValue(String str) {
Object value;
String[] strArr = str.split("=");
if (strArr.length == 2) {
value = parameterMap.get(strArr[0]);
if (value == null) {
parameterMap.put(strArr[0], strArr[1]);
} else {
if (value instanceof List) {
((List) value).add(strArr[1]);
} else {
List<String> list = new ArrayList<>(2);
list.add((String) value);
list.add(strArr[1]);
parameterMap.put(strArr[0], strArr[1]);
}
}
}
}
public String getUri() {
return uri;
}
Response这里只处理了返回简单字符串和返回静态资源文件,Response的代码如下:
public class Response {
/**
* 输出流
*/
private OutputStream outputStream;
/**
* 字符输出流
*/
private PrintWriter printWriter;
/**
* 请求类
*/
private Request request;
/**
* Cookie信息
*/
private List<Cookie> cookieList = new ArrayList<>(2);
public Response(OutputStream outputStream, Request request) {
this.outputStream = outputStream;
this.request = request;
}
public void sendStaticResource(String path) {
FileInputStream fis = null;
try {
if ("/".equals(path)) {
path = "/static/html/index.html";
} else {
path = request.getUri();
}
URL url = this.getClass().getResource(path);
if (url != null) {
File file = new File(url.getFile());
if (file.exists() && !file.isDirectory() && file.canRead()) {
fis = new FileInputStream(file);
int flag = 0;
byte[] bytes = new byte[1024];
while ((flag = fis.read(bytes)) != -1) {
outputStream.write(bytes, 0, flag);
}
}
} else {
PrintWriter printWriter = getWriter();
//这里用PrintWriter字符输出流,设置自动刷新
printWriter.write("HTTP/1.1 404 File Not Found \r\n");
printWriter.write("Content-Type: text/html\r\n");
printWriter.write("Content-Length: 23\r\n");
printWriter.write("\r\n");
printWriter.write("<h1>File Not Found</h1>");
printWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public PrintWriter getWriter() throws IOException {
printWriter = new PrintWriter(outputStream, true);
return printWriter;
}
public void sendSuccess() {
PrintWriter printWriter = null;
try {
printWriter = getWriter();
//这里用PrintWriter字符输出流,设置自动刷新
printWriter.write("HTTP/1.1 200 OK \r\n");
printWriter.write("Content-Type: text/html;charset=utf-8\r\n");
printWriter.write("Content-Length: " + "成功了".getBytes().length + "\r\n");
if (cookieList != null && !cookieList.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < cookieList.size(); i++) {
//设置多个Cookie
sb.append("Set-Cookie: ").append(cookieList.get(i).getKey()).append("=").append(cookieList.get(i).getValue()).append("\r\n");
}
printWriter.write(sb.toString());
}
printWriter.write("\r\n");
printWriter.write("成功了");
} catch (IOException e) {
e.printStackTrace();
} finally {
printWriter.close();
}
}
public void addCookie(Cookie cookie) {
cookieList.add(cookie);
}
}
这里我们模仿Servlet,也自定义一个Servlet接口。代码如下:
public interface Servlet {
void init();
void service(Request request, Response response) throws Exception;
void destory();
}
它的一个实现类如下,在这个类中我们根据URI找到对应的请求处理类,并调用响应的请求方法。
public class HttpServletImpl implements Servlet {
private StaticResourceProcessor resouce = new StaticResourceProcessor();
@Override
public void init() {
System.out.println("我被初始化了、、、、、");
}
@Override
public void service(Request request, Response response) throws Exception {
String uri = request.getUri();
if ("/".equals(uri) || (!StringUtils.isEmpty(uri) && uri.startsWith("/static/"))) {
//处理静态资源
resouce.process(request, response);
} else {
RequestMappingInfo mappingInfo = ApplicationContext.mappingMap.get(uri);
if (mappingInfo != null) {
List<String> parameterList = mappingInfo.getParameter();
int parLen = mappingInfo.getParameter().size() - 1;
Class<?>[] clazzs = mappingInfo.getFormalParameter();
List<Object> list = new ArrayList<>();
Object obj = null;
if (clazzs != null) {
for (int i = 0; i < clazzs.length; i++) {
obj = getObject(request, response, parameterList, parLen < i, clazzs[i], i);
list.add(obj);
}
}
mappingInfo.getMethod().invoke(mappingInfo.getObj(), list.toArray());
response.sendSuccess();
}
}
}
/**
* 组装方法的参数
*
* @param request
* @param response
* @param parameterList
* @param b
* @param clazz
* @param i
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Object getObject(Request request, Response response, List<String> parameterList, boolean b, Class<?> clazz, int i) throws InstantiationException, IllegalAccessException {
Object obj = null;
//如果参数类型为Request
if (clazz.isAssignableFrom(Request.class)) {
obj = request;
} else if (clazz.isAssignableFrom(Response.class)) {
//如果参数类型为Response
obj = response;
}
//如果是字节类型(包含基本类型和包装类)
else if (clazz == byte.class || clazz == Byte.class) {
if (!b) {
obj = Byte.parseByte(request.getParameterValue(parameterList.get(i)));
}
}
//如果是short类型(包含基本类型和包装类)
else if (clazz == short.class || clazz == Short.class) {
if (!b) {
obj = Short.parseShort(request.getParameterValue(parameterList.get(i)));
}
}
//如果是char类型(包含基本类型和包装类)
else if (clazz == char.class || clazz == Character.class) {
}
//如果是整型(包含基本类型和包装类)
else if (clazz == int.class || clazz == Integer.class) {
if (!b) {
obj = Integer.parseInt(request.getParameterValue(parameterList.get(i)));
}
}
//如果是float(包含基本类型和包装类)
else if (clazz == float.class || clazz == Float.class) {
if (!b) {
obj = Float.parseFloat(request.getParameterValue(parameterList.get(i)));
}
}
//如果是double(包含基本类型和包装类)
else if (clazz == double.class || clazz == Double.class) {
if (!b) {
obj = Double.parseDouble(request.getParameterValue(parameterList.get(i)));
}
}
//如果是double(包含基本类型和包装类)
else if (clazz == long.class || clazz == Long.class) {
if (!b) {
obj = Long.parseLong(request.getParameterValue(parameterList.get(i)));
}
}
//如果是boolean(包含基本类型和包装类)
else if (clazz == boolean.class || clazz == Boolean.class) {
if (!b) {
obj = Boolean.parseBoolean(request.getParameterValue(parameterList.get(i)));
}
}
//如果是boolean(包含基本类型和包装类)
else if (clazz == String.class) {
if (!b) {
obj = request.getParameterValue(parameterList.get(i));
}
}
//如果是日期类型,先不做处理
else if (clazz == Date.class) {
obj = new Date();
} else {
//暂不考虑数组、集合、Map等类型
obj = clazz.newInstance();
Field[] fields = obj.getClass().getDeclaredFields();
wrapperObjectFieldValue(request, obj, fields);
}
return obj;
}
/**
* 组装属性对象值
*
* @param request
* @param obj
* @param fields
* @throws IllegalAccessException
*/
private void wrapperObjectFieldValue(Request request, Object obj, Field[] fields) throws IllegalAccessException {
if (fields != null) {
Field field = null;
for (int j = 0; j < fields.length; j++) {
field = fields[j];
String fieldName = field.getName();
field.setAccessible(true);
String value = request.getParameterValue(fieldName);
if (value != null && !"".equals(value)) {
if (field.getType() == byte.class || field.getType() == Byte.class) {
field.set(obj, Byte.parseByte(value));
}
//如果是short类型(包含基本类型和包装类)
else if (field.getType() == short.class || field.getType() == Short.class) {
field.set(obj, Short.parseShort(value));
}
//如果是char类型(包含基本类型和包装类)
else if (field.getType() == char.class || field.getType() == Character.class) {
field.set(obj, value.toCharArray()[0]);
}
//如果是整型(包含基本类型和包装类)
else if (field.getType() == int.class || field.getType() == Integer.class) {
field.set(obj, Integer.parseInt((value)));
}
//如果是float(包含基本类型和包装类)
else if (field.getType() == float.class || field.getType() == Float.class) {
field.set(obj, Float.parseFloat((value)));
}
//如果是double(包含基本类型和包装类)
else if (field.getType() == double.class || field.getType() == Double.class) {
field.set(obj, Double.parseDouble((value)));
}
//如果是double(包含基本类型和包装类)
else if (field.getType() == long.class || field.getType() == Long.class) {
field.set(obj, Long.parseLong((value)));
}
//如果是boolean(包含基本类型和包装类)
else if (field.getType() == boolean.class || field.getType() == Boolean.class) {
field.set(obj, Boolean.parseBoolean((value)));
}
//如果是boolean(包含基本类型和包装类)
else if (field.getType() == String.class) {
field.set(obj, value);
}
}
}
}
}
@Override
public void destory() {
}
}
接着我们模仿Spring写几个注解:
模仿Spring的Autowire注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CustomAutowire {
String name() default "";
}
模仿Spring的Component注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomComponent {
}
模仿Controller注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CustomController {
}
模仿RequestMapping注解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface CustomRequestMapping {
/**
* URI
* @return
*/
String value();
/**
* 参数信息
* @return
*/
String[] parameter() default "";
}
这里根据请求找到对应的处理类和处理方法的思路是:定义一个Map,key是请求URI,value是自定义的一个类。这个自定义的类(RequestMappingInfo)包含这几个信息:Class信息、Method类、对象、请求参数和方法参数
。java类在编译为class的时候有release和debug模式之分,在命令行中直接使用javac进行编译的时候,默认的时候release模式,使用release模式会改变形参中的参数名。而IDE都是使用debug模式进行编译的。ant编译的时候,需要在ant的配置文件中指定debug="true"。 如果要修改javac编译类文件的方式的话,需要指定-g参数。即:javac -g 类文件。通常我们都是用IDE进行项目开发的,所以我们的java类在编译成class的时候参数是不会变的
,而SpringMVC在处理参数这个地方用到了ASM技术,来获取参数的信息,并且是在第一次处理请求的时候,来获取参数信息并放到缓存中,以后都从缓存中获取参数信息。RequestMappingInfo代码如下:
public class RequestMappingInfo {
/**
* 类名
*/
private Class<?> clazz;
/**
* 方法名
*/
private Method method;
/**
* 对象
*/
private Object obj;
/**
* 参数
*/
private List<String> parameter;
/**
* 方法的参数
*/
private Class<?>[] formalParameter;
//省略get set方法
}
接着我们定义一个类方便IOC:
public class BeanDefinitionInfo implements Serializable {
private static final long serialVersionUID = -5988012842492544219L;
/**
* 类信息
*/
private Class<?> clazz;
/**
* 对象
*/
private Object object;
/**
* 父类
*/
private List<Class<?>> superClass;
//省略 get set
}
接着就是我们比较重要的类了ApplicationContext,我们会在这里类中,简单模仿Spring IOC的过程,扫描固定包下固定注解的类。在这里遇到了一个问题,一开始在加载类的时候自己写了一个类加载器,但是一个类加载器在他的生命周期中只会加载这个类一次,所以会出现多次加载同一个类的情况。后来别人推荐了一个小工具类:
Reflections,这个问题才比较完美的解决,Reflections是一个很不错的工具类,可以扫描Classpath下面任意的类,并且让反射更容易。如下:扫描带某个注解的类,获取含有方法名为某个字符串的类等等。github地址在这儿:https://github.com/ronmamo/reflections,里面有很多例子。自定义的ApplicationContext的代码如下:
public class ApplicationContext {
public static final Map<String, RequestMappingInfo> mappingMap = new HashMap<>();
/**
* 所有扫描到的类
*/
private static final Map<Class<?>, BeanDefinitionInfo> allScanClazz = new HashMap<>();
private static final List<Class<?>> allClass = Lists.newArrayList();
private static Servlet servlet;
private CustomInputStreamSource streamSource = null;
public ApplicationContext(Servlet servlet, String location) {
this.servlet = servlet;
streamSource = new CustomClasspathResource(location);
}
public void init() throws Exception {
Properties properties = new Properties();
properties.load(streamSource.getInputStream());
String componentScan = properties.getProperty("component.scan");
wrapperCompontent(componentScan);
imitateIOC();
servlet.init();
}
private void wrapperCompontent(String componentScan) throws InstantiationException, IllegalAccessException {
Reflections reflection = new Reflections(componentScan);
//扫描所有有CustomController注解的类
Set<Class<?>> controllerClazz = reflection.getTypesAnnotatedWith(CustomController.class);
//扫描所有有CustomComponent注解的类
Set<Class<?>> componentClazz = reflection.getTypesAnnotatedWith(CustomComponent.class);
//扫描所有有CustomService注解的类
Set<Class<?>> serviceClazz = reflection.getTypesAnnotatedWith(CustomService.class);
for (Iterator<Class<?>> it = controllerClazz.iterator(); it.hasNext(); ) {
wrapperController(it.next());
}
componentClazz.addAll(serviceClazz);
for (Iterator<Class<?>> it = componentClazz.iterator(); it.hasNext(); ) {
Class<?> clazz = it.next();
BeanDefinitionInfo beanDefinitionInfo = new BeanDefinitionInfo();
beanDefinitionInfo.setClazz(clazz);
wrapperSuperClass(clazz, beanDefinitionInfo);
allScanClazz.put(clazz, beanDefinitionInfo);
allClass.add(clazz);
}
}
/**
* 模仿IOC
*
* @throws InstantiationException
* @throws IllegalAccessException
*/
private void imitateIOC() throws InstantiationException, IllegalAccessException {
Object instance = null;
BeanDefinitionInfo beanDefinitionInfo = null;
for (Map.Entry<Class<?>, BeanDefinitionInfo> entry : allScanClazz.entrySet()) {
Class clazz = entry.getKey();
beanDefinitionInfo = entry.getValue();
instance = beanDefinitionInfo.getObject();
if (instance == null) {
instance = clazz.newInstance();
beanDefinitionInfo.setObject(instance);
}
Field[] fields = clazz.getDeclaredFields();
if (fields != null && fields.length > 0) {
for (int i = 0; i < fields.length; i++) {
if (!fields[i].isAccessible()) {
fields[i].setAccessible(true);
}
if (AnnotationUtil.isAutowire(fields[i])) {
Class tmpClass = fields[i].getType();
if (tmpClass.isInterface()) {
BeanDefinitionInfo tmpBean = null;
for (int j = 0; j < allClass.size(); j++) {
tmpBean = allScanClazz.get(allClass.get(j));
if (tmpClass.isAssignableFrom(tmpBean.getClazz())) {
if (tmpBean.getObject() == null) {
Object tmp = tmpBean.getClazz().newInstance();
tmpBean.setObject(tmp);
}
fields[i].set(instance, tmpBean.getObject());
break;
}
}
} else {
BeanDefinitionInfo tmpBean = allScanClazz.get(tmpClass);
if (tmpBean.getObject() == null) {
tmpBean.setObject(tmpBean.getClazz().newInstance());
}
fields[i].set(instance, tmpBean.getObject());
}
}
}
}
}
}
/**
* 组装Controller
*
* @param clazz
* @throws IllegalAccessException
* @throws InstantiationException
*/
private void wrapperController(Class<?> clazz) throws IllegalAccessException, InstantiationException {
Object obj = clazz.newInstance();
BeanDefinitionInfo beanDefinitionInfo = new BeanDefinitionInfo();
beanDefinitionInfo.setClazz(clazz);
beanDefinitionInfo.setObject(obj);
wrapperSuperClass(clazz, beanDefinitionInfo);
allScanClazz.put(clazz, beanDefinitionInfo);
String str = "";
CustomRequestMapping customRequestMapping = null;
if ((customRequestMapping = isRequestMapping(clazz)) != null) {
if (customRequestMapping.value().startsWith("/")) {
str = customRequestMapping.value();
} else {
str = "/" + customRequestMapping.value();
}
}
Method[] methodArray = clazz.getMethods();
if (methodArray != null) {
RequestMappingInfo requestMappingInfo = null;
for (Method method : methodArray) {
customRequestMapping = method.getAnnotation(CustomRequestMapping.class);
if (customRequestMapping != null) {
requestMappingInfo = new RequestMappingInfo();
requestMappingInfo.setClazz(clazz);
requestMappingInfo.setMethod(method);
requestMappingInfo.setObj(obj);
Class<?>[] clazzs = method.getParameterTypes();
String strInner = "";
if (clazzs != null) {
requestMappingInfo.setFormalParameter(clazzs);
}
if (customRequestMapping.value().startsWith("/")) {
strInner = customRequestMapping.value();
} else {
strInner = "/" + customRequestMapping.value();
}
String[] parameter = customRequestMapping.parameter();
if (parameter != null && parameter.length > 0) {
requestMappingInfo.setParameter(Arrays.asList(parameter));
}
mappingMap.put(str + strInner, requestMappingInfo);
}
}
}
}
/**
* 组装父类
*
* @param clazz
* @param beanDefinitionInfo
*/
private void wrapperSuperClass(Class<?> clazz, BeanDefinitionInfo beanDefinitionInfo) {
Class<?> tmp = clazz;
List<Class<?>> superList = Lists.newArrayList();
while (tmp.getSuperclass() != null && tmp.getSuperclass() != Object.class) {
superList.add(clazz.getSuperclass());
tmp = clazz.getSuperclass();
}
beanDefinitionInfo.setSuperClass(superList);
}
public CustomRequestMapping isRequestMapping(Class<?> clazz) {
return clazz.getAnnotation(CustomRequestMapping.class);
}
public static Servlet getServlet() {
return servlet;
}
下面我们写个Controller类来测试一下:
@CustomController
@CustomRequestMapping(value = "/custom")
public class FirstPageController {
@CustomAutowire
private UserService userService;
@CustomRequestMapping(value = "/myFirstPage.do")
public void myFirstPage() {
System.out.println("我被调用了、、、、");
}
/**
* 插入操作
*
* @param userScope
*/
@CustomRequestMapping(value = "/inserUser.do")
public void inserUser(UserScope userScope, Response response) {
Cookie cookie = new Cookie("test", "testcookie");
Cookie cookie2 = new Cookie("test02", "testcookie02");
response.addCookie(cookie);
response.addCookie(cookie2);
System.out.println("我是插入操作的Controller层、、、、");
userService.insert(userScope);
}
}
我们在浏览器中输入:http://localhost:8005/custom/myFirstPage.do来看一下结果:
控制台输出如下:
返回结果如下:
和我们程序写的结果一样。
接着我们写一个稍微复杂一点的,定义一个javaBean、DAO类、Service类。
UserScope
public class UserScope implements Serializable{
private static final long serialVersionUID = -8340887359752275426L;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String passWord;
//省略get set
}
DAO
public interface UserDAO {
/**
* 插入用户信息
* @param user
* @return
*/
Integer insert(UserScope user);
}
@CustomComponent
public class UserDAOImpl implements UserDAO {
private Random random = new Random();
@Override
public Integer insert(UserScope user) {
System.out.println("我是DAO层。。。。进行插入操作......");
System.out.println(JSON.toJSONString(user));
return random.nextInt();
}
}
Service:
public interface UserService {
/**
* 插入用户信息
* @param userScope
* @return
*/
Integer insert(UserScope userScope);
}
@CustomService
public class UserServiceImpl implements UserService {
@CustomAutowire
private UserDAO userDAO;
/**
* 插入用户信息
*
* @param userScope
* @return
*/
@Override
public Integer insert(UserScope userScope) {
System.out.println("我是Service层。。。。进行插入操作......");
return userDAO.insert(userScope);
}
}
从上面的代码中我们可以看到在DAO的实现类上我们用了CustomComponent注解,在Service的实现类上我们用了CustomService的注解。在我们的那个Controller中我们又用了CustomAutowire这个注解。下面我们访问一下看看效果,我们在浏览器中输入:http://localhost:8005/custom/inserUser.do?userName=hangssewe&passWord=2ewewe
控制台输出如下:
浏览器输出为:
我们在Controller中的inserUser这个方法中设置了两个Cookie,我们来看一下Cookie有没有设置成功:
结果和我们预想的是一样的。
接着我们写一个静态资源的处理类:
public class StaticResourceProcessor {
public void process(Request request, Response response) {
response.sendStaticResource(request.getUri());
}
}
访问一下看看效果如何:
这里遇到的一个问题是在Chrome浏览器中访问的时候会报错,在IE浏览器中访问则正常显示,还没搞清楚为什么会出现这样的问题。