文章目录
本文项目见: JavaWeb: 本仓库介绍JavaWeb的三个项目。 (gitee.com)
项目流程图
JavaWeb_mvc
将各种Servlet转为一个FruitServlet。
之前的做法是,一个请求对应一个Servlet,这样Servlet太多了。所以把各种Servlet整合为一个FruitServlet。通过一个operator的值决定调用哪个Servlet。这里使用反射获取operator的值。
JavaWeb_mvc00_dispatcher
:引入使用中央控制器。
由于每一个Servlet中都有反射代码,所以继续抽取,设计一个中央控制器。JavaWeb_mvc01_controller
:优化Controller中获取参数和重定向/转发的操作,将视图处理抽取到DispatcherServlet中。
现在的DispatcherServlet类的工作分为两部分:
根据url定位到能够处理这个请求的Controller组件
- 从url中提取ServletPath:/fruit.do——fruit
- 根据fruit找到对应的FruitController组件。具体通过applicationController.xml文件,并且使用DOM技术读取配置文件,在中央控制器中形成一个beanMap容器,存放所有的对应关系。
- 根据operator的值定位到FruitController需要调用的方法。
通过反射调用Controller组件中的方法(index、add、del等)
获取参数
获取即将要调用的方法的参数签名信息: Parameter[] parameters = method.getParameters();
通过parameter.getName()获取参数的名称;准备了Object[] parameterValues 这个数组用来存放对应参数的参数值
另外,我们需要考虑参数的类型问题,需要做类型转化的工作。通过parameter.getType()获取参数的类型执行方法
Object returnObj = method.invoke(controllerBean , parameterValues);
视图处理
String returnStr = (String)returnObj;
if(returnStr.startWith(“redirect:”)){
…
}else if…
JavaWeb_mvc02_BO
在库存系统中添加业务层组件,引入IOC。这里需要我们了解MVC和IOC的基本概念。
使用ClassPathXmlApplicationContext
类创建IOC容器,在其中实现控制反转和依赖注入。
补充基础知识
Servlet
Servlet生命周期
Servlet生命周期:实例化、初始化、服务、销毁。
void init(config) - 初始化方法
//客户端发送请求,service方法自动执行。
void service(requst,response) - 服务方法
void destory() - 销毁方法
- 继承关系
- javax.servlet.
Servlet
接口- javax.servlet.
GenericServlet
抽象类- javax.servlet.http.
HttpServlet
抽象子类
- javax.servlet.http.
- javax.servlet.
- javax.servlet.
- 生命周期:从出生到死亡的过程就是生命周期。对应Servlet中的三个方法:init()、service()、destroy()。
- 默认情况下,第一次接收请求:Servlet实例化(调用构造方法)、初始化(调用init)、服务(调用service)。
从第二次请求开始:每一次都是服务。
当容器关闭:销毁服务。 - Servlet实例tomcat只会创建一个,所有的请求都通过这个实例去响应。
好处:提高系统的启动速度。
缺点:第一次请求时耗时较长。
如果需要提高第一次请求的响应速度,应该设置Servlet初始化时机。 - Servlet的初始化时机:
可以通过<load-on-startup>
来设置servlet的启动先后顺序,数字越小,启动越靠前。 - Servlet在容器中是单例的(只有一个servlet实例去响应线程)、线程不安全的。
所以:不要在servlet中定义成员变量。如果不得不定义成员变量的值,不要去修改值或做逻辑判断。
Servlet的初始化方法
Servlet中的初始化方法有两个:init() , init(config)。
//其中带参数的方法代码
public void init(ServletConfig config) throws ServletException {
this.config = config ;
init();
}
//另外一个无参的init方法如下:
public void init() throws ServletException{
}
如果我们想要在Servlet初始化时做一些准备工作,那么我们可以重写init方法。
我们可以通过如下步骤去获取初始化设置的数据
ServletConfig config = getServletConfig(); //获取config对象
config.getInitParameter(key); //获取初始化参数值
并且在web.xml文件中配置Servlet
<servlet>
<servlet-name>Demo01Servlet</servlet-name>
<servlet-class>Demo01Servlet</servlet-class>
<init-param>
<param-name>hello</param-name>
<param-value>world</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Demo01Servlet</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
也可以通过注解的方式进行配置:
@WebServlet(urlPatterns = {"/demo01"} ,
initParams = {
@WebInitParam(name="hello",value="world"),
@WebInitParam(name="uname",value="jim")
})
Servlet的服务方法
javax.servlet.http.HttpServlet
抽象类中,service不是抽象方法。
service方法执行流程:
1. String method = req.getMethod(); 获取请求的方式。
2. 判断,根据请求方式不同,决定调用不同do方法。
if (method.equals("GET")) {
this.doGet(req, resp);
} else if (method.equals("HEAD")) {
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
}
doPost方法:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
sendMethodNotAllowed方法:
private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
String protocol = req.getProtocol();
if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
小结:
- 服务方法:当有请求过来时,service方法会自动响应(其实是tomcat容器调用的)
- 在HttpServlet中的service方法会分析发送请求的方式:到底是get、post还是…然后再决定调用哪个do方法。在HttpServlet中这些do方法都是405的实现风格,所以要我们子类去实现对应的方法,否则默认会报405。
ServletContext(application)和< context-param>
配置文件中的配置如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>applicationContext.xml</param-value>
</context-param>
要想让application读取到配置文件的信息,可以用以下方法:
- 获取ServletContext。
获取ServletContext,有很多方法。
可以在初始化方法中:ServletContxt application= getServletContext();
也可以在服务方法中通过request对象获取,也可以通过session获取:
request.getServletContext();
、session.getServletContext()
- 获取上下文初始化参数:
String path = application.getInitParameter("contextConfigLocation");
MVC
MVC:Model(模型)、View(视图)、Controller(控制器)
- 视图层:用于做数据展示以及和用户交互的一个界面。
- 控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成。
- 模型层:
模型分为很多种,有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件- pojo/vo : 值对象
- DAO : 数据访问对象
- BO : 业务对象
区分业务对象和数据访问对象:
1) DAO中的方法都是单精度方法(细粒度方法)。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作…
2) BO中的方法属于业务方法,而实际的业务是比较复杂的,因此业务方法的粒度是比较粗的。举例:
注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。
那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。
注册:检查用户名是否已经被注册 - DAO中的select操作
向用户表新增一条新用户记录 - DAO中的insert操作
向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作等。
IOC
- 耦合/依赖
依赖指的是某某某离不开某某某。在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。我们设计的一个原则是: 高内聚低耦合。
即:层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合) - IOC - 控制反转 / DI - 依赖注入
控制反转:
- 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
- 这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别;
- 如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别。
- 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中。
因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转。
- 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl();
依赖注入:
- 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
那么,控制层和Service层存在耦合。 - 之后,我们将代码修改成FruitService fruitService = null ;
然后,在配置文件中配置:
<bean id="fruit" class="FruitController"> <property name="fruitService" ref="fruitService"/> </bean>
这样控制层中就存在了Service的依赖。
- 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();
- 关于XML:
概念
HTML:超文本标记语言
XML:可扩展的标记语言
可以认为:HTML是XML的子集。- XML的三个部分:
- XML声明 , 必须在文件的第一行。
- DTD 文档类型定义
- XML正文
- Java8新特性
Parameter[] parameters = method.getParameters();
String name = parameters[0].getName();
默认获取名称为args0、1等。其实可以获取到属性名。
操作:
IDEA下:文件——设置——构建、运行、部署——Java编译器——常见错误:argument type mismatch
使用反射传入pageNo时,parameterValue获取的是字符串类型。所以错误。