为员工管理添加删除的功能,即在查询结果页面中提供删除的操作链接,并实现在删除后回到查询页面的效果。如图-1
图- 1
在查询的Servlet中,输出每一行员工信息的同时,多输出一个列,内容为超链接,文字显示为“删除”字样,隐含的超链接地址为删除对应动作的Servlet,并且为了区分每一个员工信息,在向删除地址发出请求的同时,传递一个当前选中的员工的id号,以get的方式提交给服务器,服务器获取该参数,依据id构建删除语句并执行,执行之后使用重定向技术请求列表页面,重新查询,生成新的查询结果页面。
步骤一:修改ListEmpServlet,添加删除链接
如图-2所示,输出“删除”超链接
图- 2
步骤二:新建DeleteEmpServlet类,处理删除动作
如图-3所示,获取请求参数值id,构建删除语句并执行
图- 3
步骤三:修改web.xml,配置DeleteEmpServlet
ListEmpServlet.java文件代码:
package emp; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ListEmpServlet extends HttpServlet { /** * 查询员工信息列表 */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置输出流编码 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // JDBC查询员工信息 Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "xxx", "xxx"); stmt = conn.prepareStatement("select * from t_emp"); rs = stmt.executeQuery(); out.println("<html><head></head><body style='font-size:30px'>"); out.println("<table border='1' cellspacing='0' cellpadding='0' width='600px'>"); out.println("<caption>员工信息</caption>"); out.println("<tr><td>编号</td><td>姓名</td><td>薪水</td><td>年龄</td><td>操作</td></tr>"); while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); double salary = rs.getDouble("salary"); int age = rs.getInt("age"); out.println("<tr>"); out.println("<td>" + id + "</td>"); out.println("<td>" + name + "</td>"); out.println("<td>"+ salary + "</td>"); out.println("<td>" + age + "</td>"); out.println("<td><a href='delete?id="+id+"' " + "onclick=\"return confirm('是否确定删除"+name+"');\">删除</a></td>"); out.println("</tr>"); } out.println("</table></body></html>"); } catch (Exception e) { e.printStackTrace(); out.println("系统异常,请重试"); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
DeleteEmpServlet.java文件代码:
package emp; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DeleteEmpServlet extends HttpServlet{ /** * 实现删除员工信息的操作 */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取请求参数值中的id信息 response.setContentType("text/html;charset=UTF-8"); PrintWriter out =response.getWriter(); int id = Integer.parseInt(request.getParameter("id")); //连接数据库,执行删除操作 Connection conn = null; PreparedStatement stmt = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "x", "x"); stmt = conn.prepareStatement("delete from t_emp where id=?"); stmt.setInt(1, id); stmt.executeUpdate(); response.sendRedirect("list"); } catch (Exception e) { e.printStackTrace(); out.println("Error"); } finally{ if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
web.xml文件代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 增加员工 --> <servlet> <servlet-name>addEmpServlet</servlet-name> <servlet-class>emp.AddEmpServlet</servlet-class> </servlet> <!-- 查询员工信息 --> <servlet> <servlet-name>listEmpServlet</servlet-name> <servlet-class>emp.ListEmpServlet</servlet-class> </servlet> <!-- 删除员工 --> <servlet> <servlet-name>deleteEmpServlet</servlet-name> <servlet-class>emp.DeleteEmpServlet</servlet-class> </servlet> <!-- add --> <servlet-mapping> <servlet-name>addEmpServlet</servlet-name> <url-pattern>/add</url-pattern> </servlet-mapping> <!-- list --> <servlet-mapping> <servlet-name>listEmpServlet</servlet-name> <url-pattern>/list</url-pattern> </servlet-mapping> <!-- delete --> <servlet-mapping> <servlet-name>deleteEmpServlet</servlet-name> <url-pattern>/delete</url-pattern> </servlet-mapping> </web-app>
为员工管理实现修改功能。查询结果中具备修改的链接,点击后将选中的员工信息加载到表单中,修改完毕后点击“修改”按钮,回到查询页面,查看修改后的结果。如图-4
//
图- 4
在查询页面增加“修改”的超链接,并按照所选员工的id查询出一条数据,加载到表单中。当修改结束后,点击表单的“修改”那妞时,不仅仅提交表单中的修改数据,同时使用隐藏表单域,将存储的该员工id信息一同提交,服务器端收到数据后构建更新语句并执行,执行结束后使用重定向技术重新请求查询页面,生成新的查询结果,确定更新操作已成功。
步骤一:修改ListEmpServlet,增加“修改”链接
如图-5所示为增加的修改链接
图- 5
步骤二:新建LoadEmpServlet.java文件
获取请求参数值id,查询数据并构建表单显示数据,如图-6:
图- 6
步骤三:新建ModifyEmpServlet.java文件
图 - 7
步骤四:修改web.xml文件实现配置
图 - 8
ListEmpServlet.java文件:
package emp; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ListEmpServlet extends HttpServlet { /** * 查询员工信息列表 */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置输出流编码 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // JDBC查询员工信息 Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "xxx", "xxx"); stmt = conn.prepareStatement("select * from t_emp"); rs = stmt.executeQuery(); out.println("<html><head></head><body style='font-size:30px'>"); out.println("<table border='1' cellspacing='0' cellpadding='0' width='600px'>"); out.println("<caption>员工信息</caption>"); out.println("<tr><td>编号</td><td>姓名</td><td>薪水</td><td>年龄</td><td>操作</td></tr>"); while (rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); double salary = rs.getDouble("salary"); int age = rs.getInt("age"); out.println("<tr>"); out.println("<td>" + id + "</td>"); out.println("<td>" + name + "</td>"); out.println("<td>"+ salary + "</td>"); out.println("<td>" + age + "</td>"); out.println("<td><a href='delete?id="+id+"' " + "onclick=\"return confirm('是否确定删除"+name+"');\">删除</a>"); out.println("<a href='load?id="+id+"'>修改</a></td>"); out.println("</tr>"); } out.println("</table></body></html>"); } catch (Exception e) { e.printStackTrace(); out.println("系统异常,请重试"); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
LoadEmpServlet.java文件:
package emp; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoadEmpServlet extends HttpServlet { protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // 获取请求参数值id int id = Integer.parseInt(request.getParameter("id")); // 根据Id查询数据库获取员工信息 Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "xxx", "xxx"); stmt = conn.prepareStatement("select * from t_emp where id=?"); stmt.setInt(1, id); rs = stmt.executeQuery(); out.println("<html><head></head><body style='font-size:30px'>"); if (rs.next()) { String name = rs.getString("name"); double salary = rs.getDouble("salary"); int age = rs.getInt("age"); out.println("<form action='modify' method='post'>"); out.println("编号:" + id + "<br>"); out.println("<input type='hidden' name='id' value='"+id+"'/><br>"); out.println("姓名:<input name='name' value='"+name+"'/><br>"); out.println("薪水:<input name='salary' value='"+salary+"'/><br>"); out.println("年龄:<input name='age' value='"+age+"'/><br>"); out.println("<input type='submit' value='修改'/>"); out.println("</form>"); } out.println("</body></html>"); } catch (Exception e) { e.printStackTrace(); out.println("系统异常,请重试"); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
ModifyEmpServlet.java文件
package emp; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ModifyEmpServlet extends HttpServlet{ /** * 增加员工信息 */ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //0.解决中文乱码问题 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); //1.获取请求参数值 int id = Integer.parseInt(request.getParameter("id")); String name = request.getParameter("name"); double salary = Double.parseDouble(request.getParameter("salary")); int age = Integer.parseInt(request.getParameter("age")); //2.数据库操作 Connection conn = null; PreparedStatement stmt = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xxx", "xuze", "xxx"); stmt = conn.prepareStatement("update t_emp set name=?,salary=?,age=? where id=?"); stmt.setString(1, name); stmt.setDouble(2, salary); stmt.setInt(3, age); stmt.setInt(4, id); stmt.executeUpdate(); response.sendRedirect("list"); } catch (Exception e) { e.printStackTrace(); out.print("系统出现问题,稍后重试<br><p><a href='list.do'>员工信息列表</a></p>"); } finally{ if(stmt!=null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
web.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 增加员工 --> <servlet> <servlet-name>addEmpServlet</servlet-name> <servlet-class>emp.AddEmpServlet</servlet-class> </servlet> <!-- 查询员工信息 --> <servlet> <servlet-name>listEmpServlet</servlet-name> <servlet-class>emp.ListEmpServlet</servlet-class> </servlet> <!-- 删除员工 --> <servlet> <servlet-name>deleteEmpServlet</servlet-name> <servlet-class>emp.DeleteEmpServlet</servlet-class> </servlet> <!-- 加载员工 --> <servlet> <servlet-name>loadEmpServlet</servlet-name> <servlet-class>emp.LoadEmpServlet</servlet-class> </servlet> <!-- 修改员工 --> <servlet> <servlet-name>modifyEmpServlet</servlet-name> <servlet-class>emp.ModifyEmpServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>addEmpServlet</servlet-name> <url-pattern>/add</url-pattern> </servlet-mapping> <!-- list --> <servlet-mapping> <servlet-name>listEmpServlet</servlet-name> <url-pattern>/list</url-pattern> </servlet-mapping> <!-- delete --> <servlet-mapping> <servlet-name>deleteEmpServlet</servlet-name> <url-pattern>/delete</url-pattern> </servlet-mapping> <!-- load --> <servlet-mapping> <servlet-name>loadEmpServlet</servlet-name> <url-pattern>/load</url-pattern> </servlet-mapping> <!-- modify --> <servlet-mapping> <servlet-name>modifyEmpServlet</servlet-name> <url-pattern>/modify</url-pattern> </servlet-mapping> </web-app>
请求到达服务器以后,服务器是如何处理URI请求资源路径的,在与web.xml文件中的映射进行比对时的原则是什么
针对精确匹配、通配符匹配、后缀匹配三种模式修改web.xml文件中的配置,查看不同比对原则的访问结果。
步骤一:新建URIServlet.java文件
新建URIServlet.java文件,用于添加简单的输出,标识访问成功。
图 - 9
步骤二:在web.xml文件中添加精确匹配
为URIServlet.java文件添加映射,精确匹配即路径需要严格匹配,如图-10:
图 - 10
步骤三:新建uri.html文件,测试精确匹配
新建uri.html文件,添加两个超链接,地址分别为“abc.html”和“abc/abc.html”。点击不同的连接查看是否能和web.xml文件的映射规则相对应。经过测试后,如果配置模式为“/abc/abc.html”,则路径中应用名称后面的地址需要严格相等,如果只写“abc.html”的话,是不符合匹配原则,无法实现找到URIServlet并执行的。
uri.html文件如下图-11:
图 - 11
步骤四:修改web.xml文件为通配符匹配
修改web.xml中的匹配模式为通配符模式,使用*号代替任意字符,如图-12
图 - 12
步骤五:修改uri.html文件,测试通配符匹配
修改uri.html文件,再次添加两个超链接,一个地址为“abc.html”,由于该通配符前面有abc,则需要先精确匹配abc后再任意长度,所以地址为“abc.html”时,是不能够匹配成功的。第二个地址为“abc/abc/def.html”,第一个abc匹配成功后,不管后面写了任意长度任意字符都代表匹配成功,所以第二个地址可以成功访问到URIServlet。如图-13:
图 - 13
步骤六:修改web.xml文件为后缀匹配
修改web.xml中的匹配模式为后缀匹配模式,使用*.do来代替以do结尾的任意字符,如图-14:
图 - 14
步骤七:修改uri.html文件,测试后缀匹配
修改uri.html文件,再次添加两个超链接,一个地址为“abc.do”,另一个地址为“abc/ abc.do”,不管do前面有多长的字符串统统由*匹配掉了,只要结尾是do就代表匹配成功,所以两个地址都能够访问到URIServlet。如图-15
图 - 15
URIServlet.java文件代码:
package web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class URIServlet extends HttpServlet{ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("这里是URIServlet的service方法"); } }
web.xml文件代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- URI匹配 --> <servlet> <servlet-name>uri1</servlet-name> <servlet-class>web.URIServlet</servlet-class> </servlet> <!-- URI匹配 --> <!-- <servlet-mapping> <servlet-name>uri1</servlet-name> <url-pattern>/abc/abc.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>uri1</servlet-name> <url-pattern>/abc/*</url-pattern> </servlet-mapping> --> <servlet-mapping> <servlet-name>uri1</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
uri.html文件代码:
<html> <head> <body style="font-size:24"> <h3>请求资源路径的处理</h3> <ul> <li style="margin:40px">精确匹配 <ul> <li>url-pattern: /abc/abc.html <li><a href="abc.html">abc.html</a> <li><a href="abc/abc.html">abc/abc.html</a> </ul> <li style="margin:40px">通配符匹配 <ul> <li>url-pattern: /abc/* <li><a href="abc.html">abc.html</a> <li><a href="abc/abc/def.html">abc/abc/def.html</a> </ul> <li style="margin:40px">后缀匹配 <ul> <li>url-pattern: *.do <li><a href="abc.do">abc.do</a> <li><a href="abc/abc.do">abc/abc.do</a> </ul> </ul> </body> </html>
将员工管理的所有操作请求处理合并到一个Servlet中,实现请求的分发。
使用后缀匹配模式,将以do结尾的请求都提交到ActionServlet中,分析do前的操作请求种类,分发到不同的分支执行相应的动作。同时将JDBC以dao和实体的形式来实现,减少分支内的重复代码。
步骤一:新建entity.Employee类
新建与t_emp表对应的实体类,属性与表字段一一对应,添加get/set方法及构造、toString方法。结构如图-16所示
图 - 16
步骤二:新建dao.DBUtil公共类
用于实现数据库的连接和断开的工具类,结构如图-17所示
图 - 17
步骤三:新建dao.EmployeeDAO类
建立针对Employee实体的数据操作类dao。结构如图-18
图 - 18
步骤四:新建emp.ActionServlet类
创建用于进行动作分发的ActionServlet类,通过getRequestURI获取请求资源路径,分析do前面的动作种类,执行不同的分支。
图 -19
步骤五:新建addEmp.html文件
新建用于完成增加员工的表单页面。表单的action地址为ActionServlet对应的add.do,method方式为post
图 - 20
步骤六:修改web.xml文件
使用后缀匹配模式配置ActionServlet的映射原则。
图 - 21
步骤七:部署应用,访问
部署并访问工程,访问地址为http://localhost:8080/day03/list.do
entity.Employee.java文件代码:
package entity; /** * 实体类:员工属性与t_emp表中的字段匹配 */ public class Employee { private int id; private String name; private double salary; private int age; @Override public String toString() { return id + " " + name + " " + salary + " " + age; } public Employee() { super(); } public Employee(int id, String name, double salary, int age) { super(); this.id = id; this.name = name; this.salary = salary; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
dao.DBUtil.java文件代码:
package dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import org.apache.taglibs.standard.tag.common.core.OutSupport; /** * JDBC管理连接的工具类,可以获取连接和关闭连接 */ public class DBUtil { /** * 获取连接对象 */ public static Connection getConnection()throws Exception{ Connection conn = null; try { Class.forName("oracle.jdbc.OracleDriver"); conn = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:xe", "xxx", "xxx"); } catch (Exception e) { e.printStackTrace(); throw e; } return conn; } /** * 关闭连接对象 */ public static void close(Connection conn) throws Exception{ if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw e; } } } public static void main(String[] args) throws Exception{ System.out.println(getConnection()); } }
dao.EmployeeDAO文件代码:
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import entity.Employee; /** * Employee的数据操作对象,负责Employee的增删改查 */ public class EmployeeDAO { /** * 查询所有员工 */ public List<Employee> findAll() throws Exception{ List<Employee> emps = new ArrayList<Employee>(); Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try{ conn = DBUtil.getConnection(); stmt = conn.prepareStatement("select * from t_emp"); rs = stmt.executeQuery(); while(rs.next()){ Employee emp = new Employee( rs.getInt("id"), rs.getString("name"), rs.getDouble("salary"), rs.getInt("age") ); emps.add(emp); } }catch(Exception e){ e.printStackTrace(); throw e; }finally{ DBUtil.close(conn); } return emps; } /** * 删除员工信息 */ public void delete(int id) throws Exception{ Connection conn = null; PreparedStatement stmt = null; try{ conn = DBUtil.getConnection(); stmt = conn.prepareStatement("delete from t_emp where id=?"); stmt.setInt(1, id); stmt.executeUpdate(); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ DBUtil.close(conn); } } /** * 增加员工信息 */ public void save(Employee emp) throws Exception{ Connection conn = null; PreparedStatement stmt = null; try{ conn = DBUtil.getConnection(); stmt = conn.prepareStatement("insert into t_emp values(emp_id_seq.nextval,?,?,?)"); stmt.setString(1, emp.getName()); stmt.setDouble(2, emp.getSalary()); stmt.setInt(3, emp.getAge()); stmt.executeUpdate(); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ DBUtil.close(conn); } } /** * 根据id查询员工信息 */ public Employee findById(int id) throws Exception{ Employee emp = null; Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try{ conn = DBUtil.getConnection(); stmt = conn.prepareStatement("select * from t_emp where id=?"); stmt.setInt(1, id); rs = stmt.executeQuery(); if(rs.next()){ emp = new Employee( rs.getInt("id"), rs.getString("name"), rs.getDouble("salary"), rs.getInt("age") ); } }catch(Exception e){ e.printStackTrace(); throw e; }finally{ DBUtil.close(conn); } return emp; } /** * 保存修改员工信息 */ public void modify(Employee emp)throws Exception{ Connection conn = null; PreparedStatement stmt = null; try{ conn = DBUtil.getConnection(); stmt = conn.prepareStatement("update t_emp set name=?,salary=?,age=? where id=?"); stmt.setString(1, emp.getName()); stmt.setDouble(2, emp.getSalary()); stmt.setInt(3, emp.getAge()); stmt.setInt(4, emp.getId()); stmt.executeUpdate(); }catch(Exception e){ e.printStackTrace(); throw e; }finally{ DBUtil.close(conn); } } }
emp.ActionServlet文件代码:
package emp; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import dao.EmployeeDAO; import entity.Employee; public class ActionServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); // 获取请求资源路径 String uri = request.getRequestURI(); // 获取请求资源路径中除应用名以外的部分 String action = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf(".")); if (action.equals("list")) { try { EmployeeDAO dao = new EmployeeDAO(); List<Employee> emps = dao.findAll(); out.println("<table>"); out.println("<caption>员工信息列表</caption>"); out.println("<tr><td>编号</td><td>姓名</td><td>薪水</td><td>年龄</td><td>操作</td></tr>"); for (Employee emp : emps) { out.println("<tr>"); out.println("<td>" + emp.getId() + "</td>"); out.println("<td>" + emp.getName() + "</td>"); out.println("<td>" + emp.getSalary() + "</td>"); out.println("<td>" + emp.getAge() + "</td>"); out.println("<td><a href='#'>删除</a>"); out.println("<a href='#'>修改</a></td>"); out.println("</tr>"); } out.println("</table>"); out.println("<a href='addEmp.html'>增加新员工</a>"); } catch (Exception e) { e.printStackTrace(); out.print("系统繁忙"); } } else if (action.equals("add")) { String name = request.getParameter("name"); double salary = Double.parseDouble(request.getParameter("salary")); int age = Integer.parseInt(request.getParameter("age")); try { Employee emp = new Employee(); emp.setName(name); emp.setSalary(salary); emp.setAge(age); EmployeeDAO dao = new EmployeeDAO(); dao.save(emp); response.sendRedirect("list.do"); } catch (Exception e) { e.printStackTrace(); out.print("系统繁忙"); } } } }
web.xml文件代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 合并员工管理多请求--> <servlet> <servlet-name>actionServlet</servlet-name> <servlet-class>emp.ActionServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>actionServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
addEmp.html文件代码:
<html> <head> <title>addEmp.html</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> </head> <body style="font-size:24px"> <form action="add.do" method="post"> <fieldset> <legend>员工管理</legend> 姓名:<input name="name"/><br> 薪水:<input name="salary"/><br> 年龄:<input name="age"/><Br> <input type="submit" value="增加"/> </fieldset> </form> </body> </html>
Servlet生命周期的四个阶段的执行时机。
创建一个LifeServlet类,添加构造方法、init方法的重写、destroy方法的重写及service方法,通过部署动作、访问动作、停止服务器动作观察方法的执行情况及执行次数。
步骤一:创建LifeServlet类,实现四个阶段对应的四个方法
图 - 22
步骤二:修改web.xml完成配置
图 - 23
步骤三:访问Servlet查看输出
部署应用,启动服务,此时输出中没有四个方法的任何输出,在地址栏中输入url后,在控制台输出如图-24内容。构造和初始化及service都被指定,但构造和初始化只会执行这一次,再次刷新页面,会发现只有service方法被执行。如图-25所示。
图– 24
图 - 25
步骤四:修改web.xml文件,添加<load-on-startup>配置
添加配置说明,使得Servlet的实例化初始化发生在服务器启动时或部署时。
图 - 26
步骤五:重新部署,不访问查看输出
重新部署程序,但不在地址栏中访问应用,会发现实例化和初始化阶段已经被执行了。
图 - 27
步骤六:停止服务查看输出
停止服务器,第4个阶段销毁阶段执行。如图-28:
图 - 28
步骤七:修改web.xml文件,添加<init-param>配置
增加init-param配置,即增加servlet的初始参数,可以在初始化阶段读取该值。
图 - 29
步骤八:修改service方法获取init-param参数并输出
初始参数的获取,可以使用ServletConfig对象的getInitParameter方法,而ServletConfig对象使用getServletConfig()方法获取。
图 - 30
步骤九:访问service,查看参数的输出情况
图 - 31
LifeServlet.java文件代码: package web; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LifeServlet extends HttpServlet { /** * 阶段1:实例化 */ public LifeServlet() { System.out.println("1.Constructor is running ..."); } /** * 阶段2:初始化 */ @Override public void init() throws ServletException { System.out.println("2.Init is running ..."); } /** * 阶段3:就绪 */ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //读取初始化参数 ServletConfig config = getServletConfig(); String name = config.getInitParameter("company"); String address = config.getInitParameter("address"); System.out.println("Service is running ..." ); System.out.println("初始参数为:" + name+" " + address); } /** * 阶段4:销毁 */ @Override public void destroy() { super.destroy(); System.out.println("4.Destroy is running..."); } }
web.xml文件代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 生命周期 --> <servlet> <servlet-name>lifeServlet</servlet-name> <servlet-class>web.LifeServlet</servlet-class> <init-param> <param-name>company</param-name> <param-value>Tarena</param-value> </init-param> <init-param> <param-name>address</param-name> <param-value>Beijing</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 生命周期 --> <servlet-mapping> <servlet-name>lifeServlet</servlet-name> <url-pattern>/life</url-pattern> </servlet-mapping> </web-app>
实现访问网站总人数的记录,以及基于某一特定起点的访问记录。
由于网站中的资源较多,要想保留每一次的访问计数则需要一个从应用一启动就存在的空间,并且应用中的所有资源都能访问到这个存储空间,所以使用ServletContext及Servlet上下文对象保存每一次的访问计数。当计数需要基于某一个特定的数字开始时,可以使用上下文配置参数,存储在web.xml文件中,当应用启动时就可以读取到这个初始值,再实现计数。
步骤一:新建Context01Servlet.java和Context02Servlet.java文件
两个文件内容一致,获取上下文对象后判断是否是第一次访问,是第一次则初始值为1,不是第一次就将上次的值增1,如图-32所示:
图 - 32
步骤二:配置web.xml文件
为两个ContextServlet添加配置:
图 - 33
步骤三:访问不同的Servlet查看计数效果
访问两个Servlet,刷新后计数递增,并且递增后在另一个servlet中访问会基于这个递增后的数字,如图-34:
图 - 34
步骤四:修改web.xml文件,增加context-param配置
为该应用增加上下文初始参数如图-35所示。一个count-1000的键值对。通过上下文对象的getInitParameter方法可以获取该值。
图 - 35
步骤五:修改Context01和Context02,使计数从设定的初值开始
修改两个文件的代码,从初始参数开始计数,如图-36:
图 - 36
步骤六:访问不同的Servlet查看计数效果
重新部署后,交替访问两个ContextServlet,可以看到计数从初始参数开始。
图 - 37
Context01Servlet.java和Context02Servlet.java文件代码如下:
package web; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Context01Servlet extends HttpServlet{ @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); //获取全局的上下文对象 ServletContext context = getServletContext(); Object count = context.getAttribute("count"); if(count==null){ context.setAttribute("count", context.getInitParameter("count")); //context.setAttribute("count", 1); }else{ context.setAttribute("count", Integer.parseInt(count.toString())+1); } out.print("总浏览量为:"+context.getAttribute("count")); } }
web.xml文件代码如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- Servlet上下文 --> <context-param> <param-name>count</param-name> <param-value>1000</param-value> </context-param> <servlet> <servlet-name>context01Servlet</servlet-name> <servlet-class>web.Context01Servlet</servlet-class> </servlet> <servlet> <servlet-name>context02Servlet</servlet-name> <servlet-class>web.Context02Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>context01Servlet</servlet-name> <url-pattern>/context01</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>context02Servlet</servlet-name> <url-pattern>/context02</url-pattern> </servlet-mapping> </web-app>
每个Servlet只会创建一个对象实例,多个请求同时访问这个实例时,如果有修改属性的操作,那么就会有线程安全的隐患,也就是说Servlet是线程不安全的。如何避免线程不安全带来的后果?
使用Apache组织开发Apache Jmeter进行压力测试,模拟5个请求,观察线程在同时修改私有属性时产生的后果。修改Servlet中的代码,增加同步的功能以避免线程不安全带来的后果。
步骤一:新建ThreadSafeServlet类
在这个Servlet中增加一个私有属性,service方法中修改属性。模拟网络延迟,线程休眠1秒后再输出这个属性。如图-38:
图 - 38
步骤二:修改web.xml配置映射
图 -39
步骤三:使用Jmeter模拟5个HTTP请求
下载Jmeter之后,解压缩,使用命令行工具进入到解压后的bin目录下,输入“jmeter”代表启动Jmeter,然后新建测试计划(线程组。如图-40所示:
图– 40
图– 41
改写完线程数为5以后,在线程组上右键,新建HTTP请求,配置请求参数成功后,即可启动。
图– 42
图- 43
步骤四:查看控制台输出结果
图– 44
从结果中可以看到五个线程产生了修改值的冲突问题,也就是线程不安全现象。
步骤五:修改ThreadSafeServlet,增加同步功能
图 - 45
步骤六:运行Jmeter再次发送5个请求
步骤七:查看控制台输出结果
图– 46
根据图-46可以看到,使用同步后保证了线程安全,不会产生访问冲突的现象。
ThreadSafeServlet.java文件代码:
package web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ThreadSafeServlet extends HttpServlet { /** 私有属性count*/ private int count = 0; @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { synchronized (this) { count++; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + count); } } }
web.xml文件代码:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 线程安全 --> <servlet> <servlet-name>threadSafeServlet</servlet-name> <servlet-class>web.ThreadSafeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>threadSafeServlet</servlet-name> <url-pattern>/safe</url-pattern> </servlet-mapping> </web-app>