目录
1,配置说明
2,编码
3,运行结果
完整项目在这里实时更新<( ̄︶ ̄)↗[GO!]https://github.com/GoodbyeFirefly/ExpressManagementSystem
一,搭建web项目环境
1,配置说明
window10
IDEA2018.3.6(新版的IDEA创建web项目时流程有所不同,建议使用旧版)
Tomcat8.5.34
2,web项目创建过程
这里大致介绍一下,详细的创建过程可以翻一翻之前的教程。
- 从IDEA首页选择创建新项目;
- 选择Java web application;
- 在web/web-INF下创建lib目录,并添加可能用到的jar包;
- 通过project structure将lib添加至项目中,此外还要将Tomcat添加进来,否则servlet中会飘红;
- 通过绿色锤子旁边edit configurations配置Tomcat;
- 配置完成后右边的绿色小三角可以点击,运行项目弹出页面展示$END$标明配置成功;
3,将项目上传至GitHub
详细过程可以参考这里@我不想再熬夜了【IDEA上传项目到GitHub】
主要有以下几个步骤:
- 下载并安装Git;
- 在IDEA中设置Git,并登录自己的GitHub账号(已登录过的不需要重新登陆);
- 引入版本控制,创建git仓库;
- 依次通过add、commit directory将项目改动上传至暂存区、版本库中;
- 将项目分享至GitHub;
至此便可以借助GitHub来进行代码的开发,最大的好处就是可以记录每次提交的代码版本,随时回滚之前的版本,大大降低试错的成本(o゜▽゜)o☆
二,编写MVC框架(建立对框架的认知)
这里的框架是指一种映射器,将用户的请求映射到各自不同的方法,比如收集所有*.do请求,然后针对xxx.do、yyy.do调用不同的方法。
1,为什么要写这个框架?
先来看看作为小白的我之前写的web项目是什么样的
仅仅是实现一个登录、注册以及简单的商品操作就用了5个servlet文件来实现,我当时就想,像一些大的web应用那servlet该有多少?一定有某种方法简化了这种实现方式,那就是框架!
类似于这样
2,编码
1,创建DispatcherServlet
2,在web.xml中添加配置
3, 创建application.properties文件
默认在src目录下。用于配置每一个用于处理请求的类,每一个类中可能包含0-n个用于处理请求的方法
4,在DispatcherServlet中重写init方法(先暂时这样写)
public class DispatcherServlet extends javax.servlet.http.HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String path = config.getInitParameter("contentConfigLocation");
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
Properties ppt = new Properties();
try {
ppt.load(is);
} catch (IOException e) {
e.printStackTrace();
}
}
}
5,通过反射技术读取配置文件中类的注解的情况,将请求与对应的处理方法存放在map中用于后面的调用
自定义ResponseBody注解
package com.xxy.mvc;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 注解的作用:
* 被此注解添加的方法,会被用于处理请求
* 方法返回的内容,会以文字方式返回到客户端
*/
public @interface ResponseBody {
String value();
}
自定义ResponseView注解
package com.xxy.mvc;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 注解的作用:
* 被此注解添加的方法,会被用于处理请求
* 方法返回的内容,会直接重定向
*/
public @interface ResponseView {
String value();
}
定义枚举类型,标记response类型
package com.xxy.mvc;
public enum ResponseType {
TEXT, VIEW;
}
编写映射器HandlerMapping,通过读取配置文件application.properties中的类的方法以及注解,获得请求(字符串形式)与方法的对应关系
package com.xxy.mvc;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 映射器 (包含大量的网址与方法的对应关系)
*/
public class HandlerMapping {
// 静态集合,存储请求与方法的对应关系
private static Map<String, MVCMapping> data = new HashMap<>();
public static MVCMapping get(String uri) {
return data.get(uri);
}
public static void load(InputStream is) {
Properties ppt = new Properties();
try {
ppt.load(is);
} catch (IOException e) {
e.printStackTrace();
}
// 获取配置文件中描述的一个个类
Collection<Object> values = ppt.values();
for (Object cla : values) {
String className = (String) cla;
// 通过反射的方法创建对象 并获取每一个方法
try {
// 加载配置文件中描述的每一个类
Class c = Class.forName(className);
// 创建这个类的对象
Object obj = c.getConstructor().newInstance();
// 获得这个类的所有方法
Method[] methods = c.getMethods();
for (Method method : methods) {
Annotation[] as = method.getAnnotations();
if (as != null) {
for (Annotation a : as) {
if (a instanceof ResponseBody) {
// 该方法返回字符串给客户端
MVCMapping mapping = new MVCMapping(obj, method, ResponseType.TEXT);
Object o = data.put((((ResponseBody) a).value()), mapping);
if (o != null) {
// 表明存在重复的请求地址
throw new RuntimeException("请求地址重复:" + ((ResponseBody) a).value());
}
} else if (a instanceof ResponseView) {
// 该方法返回页面给客户端
MVCMapping mapping = new MVCMapping(obj, method, ResponseType.VIEW);
Object o = data.put((((ResponseView) a).value()), mapping);
if (o != null) {
// 表明存在重复的请求地址
throw new RuntimeException("请求地址重复:" + ((ResponseView) a).value());
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 映射对象,每一个对象封装了一个方法,用于处理请求
*/
public static class MVCMapping {
private Object obj;
private Method method;
private ResponseType type;
public MVCMapping() {
}
public MVCMapping(Object obj, Method method, ResponseType type) {
this.obj = obj;
this.method = method;
this.type = type;
}
public Object getObj() {
return obj;
}
public Method getMethod() {
return method;
}
public ResponseType getType() {
return type;
}
public void setObj(Object obj) {
this.obj = obj;
}
public void setMethod(Method method) {
this.method = method;
}
public void setType(ResponseType type) {
this.type = type;
}
}
}
6,在DispatcherServlet中重写service方法,通过DispatcherServlet处理*.do请求
servlet接收请求实际上是通过service方法来调用doGet、doPost方法,所以这里重写service方法时,可以将doGet、doPost方法删掉。
package com.xxy.mvc;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class DispatcherServlet extends javax.servlet.http.HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
String path = config.getInitParameter("contentConfigLocation");
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
// 加载application.properties中包含的类中对应的方法,将请求与对应方法存放在map集合中用于后续调用
HandlerMapping.load(is);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
HandlerMapping.MVCMapping mapping = HandlerMapping.get(uri);
if (mapping == null) {
resp.sendError(404, "自定义MVC:映射地址不存在" + uri);
return;
}
Object obj = mapping.getObj();
Method method = mapping.getMethod();
Object result = null;
try {
result = method.invoke(obj, req, resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
switch (mapping.getType()) {
case TEXT:
resp.getWriter().write((String) result);
break;
case VIEW:
resp.sendRedirect((String) result);
break;
}
}
}
7,实现UserController类,用于处理用户相关的请求
在application.properties中补充该类的描述
package com.xxy.test;
import com.xxy.mvc.ResponseBody;
import com.xxy.mvc.ResponseView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserController {
@ResponseBody("/login.do")
public String login(HttpServletRequest req, HttpServletResponse resp) {// HttpServletxxx 别打成Httpxxx
// 返回中文的话可能出现乱码,后面可以通过过滤器处理,这里没有必要加入到框架中(不灵活)
return "login successfully";
}
@ResponseView("/reg.do")
public String reg(HttpServletRequest req, HttpServletResponse resp) {
return "register.jsp";
}
}
3,运行结果
4,保存今天的成果
同样,选择Commit Directory,将暂存区中的代码作为一次commit提交到版本库中,如果后面项目出现问题可以通过git命令回滚到此版本。是不是很方便呢q(≧▽≦q)
通过push,可以将代码上传至GitHub中
标签:java,07,method,MVC,obj,import,编写,servlet,public From: https://blog.51cto.com/u_15849465/5803808章节汇总在这里(づ ̄3 ̄)づ╭❤~@&再见萤火虫&【07-项目训练】
对学习Java感兴趣的同学欢迎加入QQ学习交流群:1126298731
有问题欢迎提问,大家一起在学习Java的路上打怪升级!(o゜▽゜)o☆[BINGO!]