JavaWeb开发快速上手篇

参考链接:

《Java Servlet 技术简介》
《SpringMVC架构浅析》
《Spring MVC 学习指南(第二版)》

距上一次接触JavaWeb已经快6年时间了,最近因工作原因需要学习Web开发知识,这里做一个简单的记录。所以本文适合对JavaWeb开发有一定了解和基础的人群,达到快速拾起并上手的目的。

开发工具:IntelliJ IDEA
构建工具:Maven

创建工程

File -> New -> Project -> Java -> Java Web

工程目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
TestWeb
│ TestWeb.iml

├─.idea
│ │ encodings.xml
│ │ misc.xml
│ │ modules.xml
│ │ workspace.xml
│ │
│ └─artifacts
│ TestWeb_war_exploded.xml

├─out
│ └─artifacts
│ └─TestWeb_war_exploded
│ │ index.jsp
│ │
│ └─WEB-INF
│ web.xml

├─src
└─web
│ index.jsp

└─WEB-INF
│ web.xml

├─classes
└─lib

配置copile Path (将WEB-INFO/classes目录配置进来)

配置 Denpendencies (将WEB-INF/lib目录配置进来)

选择lib目录后下一步选择Jar Directory

配置tomcat

配置Configurations

菜单栏 run -> Edit Configurations 或 右上角有个向下的小箭头

新建Tomcat Server

提醒:有人说这里 可能没有 Tomcat Server 选项

第一种情况就是:你的tomcat插件没启用,这个比较简单,就是 file -> setting -> 搜索tomcat -> 点选中 -> ok

第二种情况就是:你不点下图中的加号时,可以在defaulst中找到tomcat

接下来在Edit Configurations面板的左上角点击加号,里面就有tomcat了。

在第二个选项卡Deployment中,右边有个绿色 + 加一个Artifact (这个就是访问时候的逻辑根路径)例如我配置的是/abc则访问路径为

http://localhost:8080/abc/

转换为Maven工程

  1. 项目上右键 Add Framework Support。

  2. 选择maven,点击OK。

可以看到在工程根目录下面生成了一个pom.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>java.com.test.irain</groupId>
<artifactId>TestWeb</artifactId>
<version>1.0-SNAPSHOT</version>


</project>

开始work

依赖Servlet规范包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>java.com.test.irain</groupId>
<artifactId>TestWeb</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>

</dependencies>
</project>

新建Post请求

1
2
3
4
5
6
<body style="margin-left: 50px;">
hello world, i'm successed! haha
<form action="test" method="post">
<button type="submit" value="测试按钮" style="width:100px;height:40px;margin-left: 40px;">测试</button>
</form>
</body>

创建Servlet

在刚刚依赖的maven库中我们依赖了javax.servlet,打开它的源码发现Servlet定义了5个接口方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Servlet {

//负责初始化servlet对象。容器一旦创建好servlet对象后,就调用此方法来初始化servlet对象。
void init(ServletConfig var1) throws ServletException;

//返回servlet对象初始化参数信息
ServletConfig getServletConfig();

//响应客户请求,提供服务。
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

//返回一个字符串,字符串中包含servlet的创建者,版本和版权等信息。
String getServletInfo();

//释放servlet占用的资源,销毁servlet对象。
void destroy();
}

我们碰到的大多数 Java servlet 都是为响应 Web 应用程序上下文中的 HTTP 请求而设计的。因此,javax.servlet 和 javax.servlet.http 包中特定于 HTTP 的类是我们应该关心的。

在创建一个 Java servlet 时,一般需要子类 HttpServlet。该类中的方法允许您访问请求和响应包装器(wrapper),您可以用这个包装器来处理请求和创建响应。

1
2
3
4
5
6
7
8
9
public class TestServlet extends HttpServlet {

@Override
protected void service(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
String buttonValue = req.getParameter("button");
System.out.println("buttonValue = " + buttonValue);
}
}

配置web.xml的servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.test.irain.TestServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>

该文件向 Tomcat 定义了 Web 应用程序。该文件中的 servlet-name 元素命名了所使用的 servlet。servlet-class 元素将该名称映射到一个特定的类,该类定义了 servlet,即 HelloWorldServlet(本示例中)。servlet-mapping 元素告诉 Tomcat /test(本例中)形式的 URL 映射我们的 servlet,这是由映射的 servlet 类定义的。

一旦设置好该文件,就可以启动 Tomcat 并能看到 servlet 加载。

控制台输出结果:

1
buttonValue = 测试按钮

Spring MVC 架构

顾名思义,Spring MVC是基于MVC框架的, 为解决持久层中一直未处理好的数据库事务的编程,又为了迎合 NoSQL 的强势崛起,Spring MVC 给出了方案:

小试牛刀

接下来将我们的工程转为spring mvc工程:

  1. 项目上右键 Add Framework Support。

  2. 选择spring mvc,点击OK。

WEB-INFO目录多了两个xml文件:

1
2
3
4
5
6
7
8
9
│  index.jsp
│ index2.html

└─WEB-INF
│ applicationContext.xml
│ dispatcher-servlet.xml
│ web.xml

└─lib

修改web.xml中的url-pattern 元素的值改为 / ,表示要拦截所有的请求,并交由Spring MVC的后台控制器来处理,改完之后:

1
2
3
4
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

修改dispatcher-servlet.xml文件

这个文件名的开头 dispatcher 与上面 web.xml 中的 <servlet-name> 元素配置的 dispatcher 对应,这是 Spring MVC 的映射配置文件(xxx-servlet.xml),我们编辑如下:

1
2
3
4
5
6
7
8
9
10
<bean id="simpleUrlHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- /hello 路径的请求交给 id 为 helloController 的控制器处理-->
<prop key="/hello">helloController</prop>
</props>
</property>
</bean>
<bean id="helloController" class="com.test.irain.controller.HelloController"></bean>

编写 HelloController

1
2
3
4
5
6
7
8
9
10
public class HelloController implements Controller {

public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
//Spring MVC 通过 ModelAndView 对象把模型和视图结合在一起
ModelAndView mav = new ModelAndView("index.jsp");
mav.addObject("message", "Hello Spring MVC");
return mav;
}
}

修改index.jsp文件如下:

1
2
3
4
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false"%>

<h1>${message}</h1>

重启服务器,输入地址:localhost/abc/hello

过程分析

第一步:DispatcherServlet拦截请求

从请求离开浏览器以后,第一站到达的就是 DispatcherServlet,看名字这是一个 Servlet,通过 J2EE 的学习,我们知道 Servlet 可以拦截并处理 HTTP 请求,DispatcherServlet 会拦截所有的请求,并且将这些请求发送给 Spring MVC 控制器。

1
2
3
4
5
6
7
8
9
10
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

第二步:处理器映射

处理器映射会根据请求所携带的 URL 信息来进行决策,例如上面的例子中,我们通过配置 simpleUrlHandlerMapping 来将 /hello 地址交给 helloController 处理。

第三步:控制器处理

一旦选择了合适的控制器, DispatcherServlet 会将请求发送给选中的控制器,到了控制器,请求会卸下其负载(用户提交的请求)等待控制器处理完这些信息。

第四步:返回 DispatcherServlet

当控制器在完成逻辑处理后,通常会产生一些信息,这些信息就是需要返回给用户并在浏览器上显示的信息,它们被称为模型(Model)。仅仅返回原始的信息时不够的——这些信息需要以用户友好的方式进行格式化,一般会是 HTML,所以,信息需要发送给一个视图(view),通常会是 JSP。

第五步:视图解析器

上面的例子是直接绑定到了 index.jsp 视图,实际中我们传递给 DispatcherServlet 的视图名并不直接表示某个特定的 JSP。(实际上,它甚至不能确定视图就是 JSP)相反,它传递的仅仅是一个逻辑名称,这个名称将会用来查找产生结果的真正视图。

注解配置

在 dispatcher-servlet.xml 文件中,删掉之前的配置,然后增加一句组件扫描:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 扫描controller下的组件 -->
<context:component-scan base-package="com.test.irain.controller"/>
</beans>

把接口实现去掉,并添加两个注解

1
2
3
4
5
6
7
8
9
10
11
@org.springframework.stereotype.Controller
public class HelloController{

@RequestMapping("/hello")
public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mav = new ModelAndView("index.jsp");
mav.addObject("message", "Hello Spring MVC");
return mav;
}
}

这RequestMapping还可以作用在类上面,就相当于是给该类所有配置的映射地址前加上了一个地址。