IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

[JavaWeb教程]第三章-Servlet开发

孙豪杰的博客 2016-03-07 23:37:40 累计浏览 3,075 次
本机暂存

前面我们介绍到了form表单,其中action属性是把表单数据提交的路径,那么数据在服务器端是怎么处理的呢?我们一起来学习一下java servlet开发实现数据在服务器端的处理。

servlet是程序必须运行在java web服务器中,主要有tomcat, jboss,jetty中,这里我们使用比较常用的tomcat作为java web服务器。下面简单介绍一下tomcat的安装:
1、tomcat下载:http://pan.baidu.com/s/1mho8L1u
2、找一个合适的目录把下载的文件解压就好了,比如我的就是在:”D:\Program Files”,目录为“apache-tomcat-8.0.21”
3、与eclipse集成:windows->preferences->Server->Runtime Environment

tomcat配置3

选中Apache-Apache Tomcat 8.0 然后Next

tomcat配置2

4、运行web工程
在项目上点击右键Run As - Run On Server-Apache- tomcat v8.0 Server

tomcat配置3

Next->Finish
5、通过浏览器查看前面开发的界面
http://localhost:8080/learntestweb/helloworld.html
在浏览器中显示了”Hello World!”,查看本机的ip,把localhost替换成本机ip在局域网内也可以访问的。
这里的”learntestweb”是站点路径,后面的是链接路径。

上面的访问虽然通过浏览器访问服务器路径获取的页面,但是仍然是静态页面,下面我们一起使用servlet输出”当前时间+hello world”。
新创建类com.sunhaojie.learntestweb.web.HelloWorldServlet

publicclassHelloWorldServlet extendsHttpServlet {
    @Override
    publicvoiddoGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        doPost(req, resp);
    }
    @Override
    publicvoiddoPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd HH:mm:SS");
        Date curDate = newDate();
        String curDateStr = dateFormat.format(curDate);
        String helloWorld = curDateStr + " : hello world!";
        resp.getWriter().println(helloWorld);
    }
}  

其中doGet和doPost就是对应了form提交方法中的get和post方法。
“resp. getWriter()”获取输出流,println把数据输出到客户端,这里不用调用输出流的close方法。
在web.xml中添加配置
[pre lang=”xml”]
<servlet>
<servlet-class>com.sunhaojie.learntestweb.web.HelloWorldServlet</servlet-class>
<servlet-name>helloWorld</servlet-name>
</servlet>

<servlet-mapping>
<servlet-name>helloWorld</servlet-name>
<url-pattern>/helloWorld</url-pattern>
</servlet-mapping>
[/pre]
这个配置是把url路径映射到类上,这里是把路径“/helloWorld”映射到”com.sunhaojie.learntestweb.web.HelloWorldServlet”上。

我们使用上一章的学生信息表,把学生信息提交到服务器端(因为上传文件比较复杂,并且不常用,这里先不介绍了)。把form.html复制为studentForm.html,然后把file表单删除,并修改action=“/learntestweb/submitStudentInfo”,在web.xml添加submitStudentInfo路径的映射
[pre lang=”xml”]
<servlet>
<servlet-class>com.sunhaojie.learntestweb.web.SubmitStudentInfoServlet</servlet-class>
<servlet-name>submitStudentInfo</servlet-name>
</servlet>

<servlet-mapping>
<servlet-name>submitStudentInfo</servlet-name>
<url-pattern>/submitStudentInfo</url-pattern>
</servlet-mapping>
[/pre]
创建SubmitStudentInfoServlet类,把提交的信息复制给StudentVo类,并保存。
代码如下:

publicclassStudentVo {
    privateString name;
    privateString sex;
    privateString year;
    privateString month;
    privateString day;
    privateString[] hobbys;
    privateString password;
    privateString info; 
} 
publicclassSubmitStudentInfoServlet extendsHttpServlet {
    @Override
    protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        doPost(req, resp);
    }
    @SuppressWarnings("unchecked")
    @Override
    protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String name = req.getParameter("name");
        String sex = req.getParameter("sex");
        String year = req.getParameter("year");
        String month = req.getParameter("month");
        String day = req.getParameter("day");
        String[] hobbys = req.getParameterValues("hobby");
        String password = req.getParameter("password");
        String info = req.getParameter("info");
        StudentVo studentVo = newStudentVo();
        studentVo.setName(name);
        studentVo.setSex(sex);
        studentVo.setYear(year);
        studentVo.setMonth(month);
        studentVo.setDay(day);
        studentVo.setHobbys(hobbys);
        studentVo.setPassword(password);
        studentVo.setInfo(info);
        List&lt;StudentVo&gt; studentVoList = (List&lt;StudentVo&gt;) req.getSession().getAttribute("studentList");
        if(studentVoList == null) {
            studentVoList = newArrayList&lt;StudentVo&gt;();
            req.getSession().setAttribute("studentList", studentVoList);
        }
        studentVoList.add(studentVo);
        resp.setContentType("text/html; charset=UTF-8");
        resp.getWriter().print(("当前学生信息总数为:"+ studentVoList.size()));
    }
}  

知识点:
1、req.setCharacterEncoding(“UTF-8”);设置入参编码方式,为了处理中文乱码。
2、req.getParameter(“xxx”),获取key为xxx的参数值,这里是form表单中name属性为xxx的值
3、req.getParameterValues(“xxx”),获取key为xxx的参数值数组,用于key相同的多值传输数据。
4、req.getSession(). getAttribute(“xxx”);获取回话session中的属性xxx的值,我们后面再看一下session。
还有一个setAttribute是为session的属性赋值。
5、resp.setContentType设置内容类型,这里为了处理中文乱码问题。
大家多次提交发现学生信息的总数再添加,那么我们使用一个另外的浏览器再次访问(或者关掉当前浏览器,重新打开)发现学生信息数从0开始了。我们提交到同一个服务器,数据应该都在浏览器直接共享才是我们要的效果,否则提交到服务器端没有意义啦。下面我们修改一下功能:

List&lt;StudentVo&gt; studentVoList = (List&lt;StudentVo&gt;) req.getServletContext().getAttribute("studentList");
if(studentVoList == null) {
    studentVoList = newArrayList&lt;StudentVo&gt;();
    req.getServletContext().setAttribute("studentList", studentVoList);
}  

把getSession替换成getServletContext,重启服务,不同的浏览器提交学生信息个数都在增加。

下面我们来普及几个概念:
request,请求,前面我们学习Socket时,讲到了socket有一个输入流,一个输出流,用于客户端和服务器端之间通信。这里的request就可以理解为输入流的封装,实现了客户端和服务器端的http交互。
response,应答,输出流的封装。
session,每次点击,提交数据都是一次交互,客户端(这里可以理解为浏览器)和服务器端的一段时间内的全部的交互称为回话(session),session有过期时间,两次请求超出了服务器设置(可变更)的session过期时间,第二次请求就会创建新的回话。
cookie,客户端按照域名存储的键值对信息,可以持久化到硬盘。键值对中有一个key sessionId(也可以变更,但是作用类似)是实现session的关键数据。当客户端访问服务器端时,服务器端会查看是否存在sessionId如果存在,则会把本次请求和session关联,如果不存在则创建新的session,并把sessionId赋值给请求的cookie,客户端会把cookie信息在本地保存。大部分的sessionId的cookie信息时内存存储,没有持久化到硬盘,所以重启浏览器会导致创建新的session。
servletContext,实例容器,每个web服务器存在一个servletContext,启动时创建,关闭时销毁,所以我们重启服务后学生信息个数被清空。

我们如果想查看已经提交的学生信息,使用输出流打印一个页面,字符串的拼接太复杂了,所以我们引入一个模板引擎velocity可以更方便的生成页面信息。
添加velocity模板支持,在工程的WEB-INFO下的lib目录(如果不存在,则新建lib目录)中添加以下jar包。
http://pan.baidu.com/s/1eQOwYQ2 velocity-tools-2.0.jar
http://pan.baidu.com/s/1mhfLNz6 velocity-1.7.jar
http://pan.baidu.com/s/1o6P2BJs commons-logging-1.1.jar
http://pan.baidu.com/s/1geqLub5 commons-lang-2.2.jar
http://pan.baidu.com/s/1boiMc0n commons-digester-1.8.jar
http://pan.baidu.com/s/1sk5tVTb commons-collections-3.2.jar
http://pan.baidu.com/s/1i4lX8Nz commons-beanutils-1.7.0.jar
在WEB-INFO下创建文件velocity.properties,内容为:
[pre lang=”xml”]
resource.loader = webapp
webapp.resource.loader.class = org.apache.velocity.tools.view.servlet.WebappLoader
webapp.resource.loader.path=/WEB-INF/vm/
input.encoding=utf-8
output.encoding=utf-8
[/pre]

创建业务处理类StudentListServlet

publicclassStudentListServlet extendsVelocityViewServlet {
    @Override
    protectedTemplate handleRequest(HttpServletRequest request, HttpServletResponse response, Context ctx) {
        List&lt;StudentVo&gt; studentList = (List&lt;StudentVo&gt;) request.getServletContext().getAttribute("studentList");
        ctx.put("studentList", studentList);
        returngetTemplate("studentList.vm");
    }
}  

这里注意继承的是velocity提供的Servlet基类,其中Context.put(“key”, value);表示在模板中可以获取的数据,key为第一个入参。
创建vm模板页面studentList.vm 用于展示学生信息列表
[pre lang=”xml”]
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>学生信息列表</title>
</head>
<body>
<div align=”center”>
<h2>学生信息表</h2>
<table border=”1″ width=”50%”>
<tr>
<th width=”10%”>姓名</th>
<th width=”10%”>性别</th>
<th width=”10%”>生日</th>
<th width=”15%”>爱好</th>
<th width=”15%”>初始密码</th>
<th width=”45%”>自我介绍</th>
</tr>
#foreach( $item in $studentList)
<tr>
<td>$item.name</td>
<td>
#if(“male” == $item.sex)

#elseif(“female” == $item.sex)

#else
未知
#end
</td>
<td>${item.year}-${item.getMonth()}-${item.day}</td>
<td>
#foreach( $h in $item.hobbys)
$h
#end
</td>
<td>$item.password</td>
<td>$item.info</td>
</tr>
#end
</table>
</div>
</body>
</html>
[/pre]
1、$xxxx或者${xxxx}获取在Context.put的数据,xxxx为第一个入参的值。
2、${xxxx.yyy}获取xxxx对象中的yyy属性,我们也可以使用${xxxx.get()}调用方法获取。
3、foreach方法,foreach( $item in $studentList)遍历集合studentList,$item表示一个元素。结尾使用#end
4、ifelse,分支流程控制,#end结尾
web.xml配置
[pre lang=”xml”]
<servlet>
<servlet-name>StudentListServlet</servlet-name>
<servlet-class>com.sunhaojie.learntestweb.web.StudentListServlet</servlet-class>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/velocity.properties</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>StudentListServlet</servlet-name>
<url-pattern>/studentList</url-pattern>
</servlet-mapping>
[/pre]
init-param可以理解为构造函数的入参,获取vilocity配置。
浏览器访问:http://localhost:8080/learntestweb/studentList 可以展示出来服务器中保存的学生信息数据了。

页面端的入门开发基本讲完了,服务器端重启数据丢失的问题怎么解决呢?

小练习:
开发学生信息编辑功能,已注册的用户可以更新信息。

以下是工程中使用的代码:
web.xml
[pre lang=”xml”]
<!DOCTYPE web-app PUBLIC
“-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”
“http://java.sun.com/dtd/web-app_2_3.dtd” >
<web-app>
<display-name>learntestweb</display-name>

<servlet>
<servlet-class>com.sunhaojie.learntestweb.web.HelloWorldServlet</servlet-class>
<servlet-name>helloWorld</servlet-name>
</servlet>

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

<servlet>
<servlet-class>com.sunhaojie.learntestweb.web.SubmitStudentInfoServlet</servlet-class>
<servlet-name>submitStudentInfo</servlet-name>
</servlet>

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

<servlet>
<servlet-name>StudentListServlet</servlet-name>
<servlet-class>com.sunhaojie.learntestweb.web.StudentListServlet</servlet-class>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/velocity.properties</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>StudentListServlet</servlet-name>
<url-pattern>/studentList</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>helloworld.html</welcome-file>
</welcome-file-list>
</web-app>
[/pre]

velocity.properties:
[pre lang=”xml”]
resource.loader = webapp
webapp.resource.loader.class = org.apache.velocity.tools.view.servlet.WebappLoader
webapp.resource.loader.path=/WEB-INF/vm/
input.encoding=utf-8
output.encoding=utf-8
[/pre]

studentForm.html
[pre lang=”html”]
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>学生信息录入表单</title>
</head>
<body>
<div align=”center”>
<h1>学生信息提交</h1>
<form action=”/learntestweb/submitStudentInfo” method=”post”>
<table border=”1″>
<tr>
<td align=”right” width=”30%”><label for=”nameTextId”>姓名:</label></td>
<td align=”left”><input type=”text” name=”name” id=”nameTextId”/></td>
</tr>
<tr>
<td align=”right”><label>性别:</label></td>
<td align=”left”><input type=”radio” name=”sex” value=”male” /> 男 <input type=”radio” name=”sex” value=”female” /> 女 </td>
</tr>
<tr>
<td align=”right”><label>出生日期:</label></td>
<td align=”left”>
<select name=”year”>
<option selected=”selected”>—-年—-</option>
<option >1990</option>
<option >1991</option>
<option >1992</option>
<option >1993</option>
<option >1994</option>
</select>
<select name=”month”>
<option selected=”selected”>—-月—-</option>
<option >01</option>
<option >02</option>
<option >03</option>
<option >04</option>
<option >05</option>
<option >06</option>
<option >07</option>
<option >08</option>
<option >09</option>
<option >10</option>
<option >11</option>
<option >12</option>
</select>
<select name=”day”>
<option selected=”selected”>—-日—-</option>
<option >01</option>
<option >02</option>
<option >03</option>
<option >04</option>
<option >05</option>
<option >06</option>
<option >07</option>
<option >08</option>
<option >09</option>
<option >10</option>
<option >11</option>
<option >12</option>
<option >13</option>
<option >14</option>
<option >15</option>
<option >16</option>
<option >17</option>
<option >18</option>
<option >19</option>
<option >20</option>
<option >21</option>
<option >22</option>
<option >23</option>
<option >24</option>
<option >25</option>
<option >26</option>
<option >27</option>
<option >28</option>
<option >29</option>
<option >30</option>
<option >31</option>
</select>
</td>
</tr>
<tr>
<td align=”right”><label>兴趣爱好:</label></td>
<td align=”left”>
<input type=”checkbox” name=”hobby” value=”basketball” />篮球
<input type=”checkbox” name=”hobby” value=”football” />足球
<input type=”checkbox” name=”hobby” value=”swim” />游泳
</td>
</tr>
<tr>
<td align=”right”><label>初始密码:</label></td>
<td align=”left”><input type=”password” name=”password”/></td>
</tr>
<tr>
<td align=”right”><label>自我介绍:</label></td>
<td align=”left”><textarea rows=”5″ cols=”20″ name=”info”></textarea></td>
</tr>
<tr>
<td align=”center” colspan=”2″>
<input type=”reset” value=”重置”/> <input type=”submit” value=”提交” /> <input type=”button” value=”按钮” />
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
[/pre]

studentList.vm
[pre lang=”html”]
<!DOCTYPE html>
<html>
<head>
<meta charset=”UTF-8″>
<title>学生信息列表</title>
</head>
<body>
<div align=”center”>
<h2>学生信息表</h2>
<table border=”1″ width=”50%”>
<tr>
<th width=”10%”>姓名</th>
<th width=”10%”>性别</th>
<th width=”10%”>生日</th>
<th width=”15%”>爱好</th>
<th width=”15%”>初始密码</th>
<th width=”45%”>自我介绍</th>
</tr>
#foreach( $item in $studentList)
<tr>
<td>$item.name</td>
<td>
#if(“male” == $item.sex)

#elseif(“female” == $item.sex)

#else
未知
#end
</td>
<td>${item.year}-${item.month}-${item.day}</td>
<td>
#foreach( $h in $item.hobbys)
$h
#end
</td>
<td>$item.password</td>
<td>$item.info</td>
</tr>
#end
</table>
</div>
</body>
</html>
[/pre]

packagecom.sunhaojie.learntestweb.web;
importjava.io.IOException;
importjava.text.DateFormat;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
/**
 * @ClassName HelloWorldServlet
 * @Description 输出当前时间和hello world的字符串
 *
 * @author sunhaojie 3113751575@qq.com
 * @date 2016年2月23日 上午10:49:11
 */
publicclassHelloWorldServlet extendsHttpServlet {
    @Override
    publicvoiddoGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        doPost(req, resp);
    }
    @Override
    publicvoiddoPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd HH:mm:SS");
        Date curDate = newDate();
        String curDateStr = dateFormat.format(curDate);
        String helloWorld = curDateStr + " : hello world!";
        resp.getWriter().println(helloWorld);
    }
}
packagecom.sunhaojie.learntestweb.web;
 
importjava.io.IOException;
importjava.util.ArrayList;
importjava.util.List;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importcom.sunhaojie.learntestweb.vo.StudentVo;
 
/**
 * @ClassName SubmitStudentInfoServlet
 * @Description 学生信息提交
 *
 * @author sunhaojie 3113751575@qq.com
 * @date 2016年2月23日 下午2:02:08
 */
publicclassSubmitStudentInfoServlet extendsHttpServlet {
 
    @Override
    protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        doPost(req, resp);
    }
 
    @SuppressWarnings("unchecked")
    @Override
    protectedvoiddoPost(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String name = req.getParameter("name");
        String sex = req.getParameter("sex");
        String year = req.getParameter("year");
        String month = req.getParameter("month");
        String day = req.getParameter("day");
        String[] hobbys = req.getParameterValues("hobby");
        String password = req.getParameter("password");
        String info = req.getParameter("info");
        System.out.println(name);
        StudentVo studentVo = newStudentVo();
        studentVo.setName(name);
        studentVo.setSex(sex);
        studentVo.setYear(year);
        studentVo.setMonth(month);
        studentVo.setDay(day);
        studentVo.setHobbys(hobbys);
        studentVo.setPassword(password);
        studentVo.setInfo(info);
 
        List&lt;StudentVo&gt; studentVoList = (List&lt;StudentVo&gt;) req.getServletContext().getAttribute("studentList");
        if(studentVoList == null) {
            studentVoList = newArrayList&lt;StudentVo&gt;();
            req.getServletContext().setAttribute("studentList", studentVoList);
        }
        studentVoList.add(studentVo);
 
        resp.setContentType("text/html; charset=UTF-8");
        resp.getWriter().print(("当前学生信息总数为:"+ studentVoList.size()));
    }
}
 
packagecom.sunhaojie.learntestweb.web;
importjava.util.List;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importorg.apache.velocity.Template;
importorg.apache.velocity.context.Context;
importorg.apache.velocity.tools.view.VelocityViewServlet;
importcom.sunhaojie.learntestweb.vo.StudentVo;
/**
 * @ClassName StudentListServlet
 * @Description 学生信息列表
 *
 * @author sunhaojie 3113751575@qq.com
 * @date 2016年2月23日 下午4:33:28
 */
publicclassStudentListServlet extendsVelocityViewServlet {
    @Override
    protectedTemplate handleRequest(HttpServletRequest request, HttpServletResponse response, Context ctx) {
        List&lt;StudentVo&gt; studentList = (List&lt;StudentVo&gt;) request.getServletContext().getAttribute("studentList");
        ctx.put("studentList", studentList);
        returngetTemplate("studentList.vm");
    }
}

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. SmartSprites - 命令行形式的CSS Sprites生成器 (累计阅读 123,894)
  2. 程序员技术练级攻略 (累计阅读 35,468)
  3. Java开发岗位面试题归类汇总 (累计阅读 22,155)
  4. android 开发入门 (累计阅读 19,527)
  5. 我的PHP,Python和Ruby之路 (累计阅读 13,146)
  6. HashMap解决hash冲突的方法 (累计阅读 12,652)
  7. Hello! 404 (累计阅读 9,384)
  8. 一个大二学生有关如何成为一名软件工程师的疑问及答复 (累计阅读 9,178)
  9. 优雅绝妙的Javascript跨域问题解决方案 (累计阅读 8,067)
  10. Java程序员应该知道的10个eclipse调试技巧 (累计阅读 8,011)