Servlet JSP
Java Web应用的目录结构
Java Servlet 规范规定了严谨的目录结构必须
webapp
|--WEB-INF 用户不能直接访问的文件夹
| |-- web.xml 部署描述文件
| |-- classes 编译以后的Java 类文件, 包括Servlet等
| |-- lib 第三方的库, 比如jdbc驱动等
|--post.html 直接发布的文件: html, js, css 等
Eclipse会自动将项目发布到 Tomcat 中:
Servlet JDBC 编程
导入JDBC驱动
Maven项目中导入的Jar会自动发布到 WEB-INF/lib 文件夹中.
步骤:
-
导入 mysql 驱动
<dependency> <groupId>mysql-connector-java</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency>
部署
检查 Tomcat 里面的Web应用中WEB-INF/lib里面是否有mysql connector jdbc jar.
导入测试框架 JUnit
JUnit是企业中必备的Java测试工具, 其使用步骤为:
-
导入JUnit组件
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
这里
<scope></scope>
表示JUnit组件不发布到Web 应用的WEB-INF/lib文件夹下,只是在Eclipse项目中有效
scope 范围 -
创建测试案例:
public class TestCase { @Test public void testHello() { System.out.println("Hello World!"); } @Test public void testKitty() { System.out.println("Hello Kitty!"); } }
测试: 在Eclipse中可以对每个测试方法单独执行, 测试结果显示在JUnit视图标签中.
编写DBUtils封装数据库连接
-
编写DBUtil
public class DBUtil { private static String driver; private static String url; private static String username; private static String password; //读取配置文件,获取4个连接参数 conf.properties static{ try { //读取resource中的配置文件 String file="conf.properties"; InputStream in = DBUtil.class .getClassLoader() .getResourceAsStream(file); Properties config=new Properties(); config.load(in); driver=config.getProperty("driver"); url=config.getProperty("url"); username=config.getProperty("username"); password=config.getProperty("password"); //打桩!!! } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public static Connection getConnection() throws SQLException { try { Class.forName(driver); Connection conn = DriverManager.getConnection( url, username, password); return conn; } catch (ClassNotFoundException e) { e.printStackTrace(); throw new SQLException(e); } } public static void commit(Connection conn){ if(conn!=null){ try { conn.commit(); } catch (SQLException e) { e.printStackTrace(); } } } public static void rollback(Connection conn){ if(conn!=null){ try { conn.rollback(); } catch (SQLException e) { e.printStackTrace(); } } } public static void close(Connection conn){ if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
-
利用JUnit测试:
@Test public void testCConnection() throws SQLException { //测试数据库的连接 Connection conn = DBUtil.getConnection(); System.out.println(conn); DBUtil.close(conn); }
Servlet直接调用JDBC可以直接编写程序,程序会复杂繁琐:
步骤为:
-
编写Servlet
/** * 实现显示用户列表的功能 */ public class ListUserServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //连接到数据库 //查询结果 //将查询结果拼接为HTML //返回HTML内容 //状态默认值是200 response.setContentType("text/html;charset=utf-8"); //设置Body中的文本编码为 utf-8 response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); //输出头部 out.println("<!DOCTYPE html>"); out.println("<html>"); out.println(" <head>"); out.println(" <meta charset=\"utf-8\""); out.println(" </head>"); out.println(" <body>"); out.println(" <h1>用户列表</h1>"); Connection conn = null; try { conn = DBUtil.getConnection(); //执行SQL String sql = "select * from user"; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql); //输出头部... out.println("<table border='1'>"); out.println(" <tr>"); out.println(" <td>编号</td>"); out.println(" <td>用户名</td>"); out.println(" <tr>"); while(rs.next()) { //读取查询结果 //输出 每一行数据 out.println(" <tr>"); out.print(" <td>"); out.print(rs.getInt("id")); out.println(" </td>"); out.print(" <td>"); out.print(rs.getString("username")); out.println(" </td>"); out.println(" </tr>"); } //输出尾部 out.println(" </table>"); } catch (SQLException e) { e.printStackTrace(); //抛出异常返回 500 错误页面 throw new ServletException(e); } finally { DBUtil.close(conn); } out.println(" </body>"); out.println("</html>"); } }
拼接table的思路如下:
-
配置web.xml
<servlet> <description></description> <display-name>ListUserServlet</display-name> <servlet-name>ListUserServlet</servlet-name> <servlet-class>day03.ListUserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListUserServlet</servlet-name> <url-pattern>/user/list</url-pattern> </servlet-mapping>
-
测试:
http://localhost:8080/servlet1/user/list
利用MVC模式实现用户列表功能
上述案例可以看到, 数据访问代码和HTML代码混合在一起, 混乱不堪, 并且当HTML页面内容复杂时候, 就更加难于驾驭代码.
在WEB编程中采用MVC模式, 将数据访问\显示视图和控制流程加以分离, 这样可以应付复杂HTML页面处理.
实现步骤
- 编写实体类User:
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private String email;
private String mobile;
private Date createTime;
public User() {
}
public User(Integer id, String username, String password, String email, String mobile, Date createTime) {
super();
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.mobile = mobile;
this.createTime = createTime;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", email=" + email + ", mobile="
+ mobile + ", createTime=" + createTime + "]";
}
}
-
编写Dao封装数据访问逻辑
Dao 接口:
public interface UserDao { /** * 查询全部用户信息 * @return 包含全部用户信息的集合 */ List<User> findAllUser(); }
Dao实现类:
public class UserDaoImpl implements UserDao{ public List<User> findAllUser() { Connection conn = null; try { conn = DBUtil.getConnection(); String sql = "select * from user"; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql); List<User> list = new ArrayList<User>(); while(rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setEmali(rs.getString("email")); user.setMobile(rs.getString("mobile")); user.setCreateTime(rs.getTimestamp("create_time")); list.add(user); } return list; } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } finally { DBUtil.close(conn); } } }
-
测试Dao
@Test public void testFindAllUser(){ //测试 查询全部用户信息的方法 UserDao dao = new UserDaoImpl(); List<User> list=dao.findAllUser(); for (User user : list) { System.out.println(user); } }
-
编写 ListAllServlet 作为控制器
public class ListAllServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //利用Dao查询数据 //将请求转发到 另外一个 Servlet显示数据 UserDao dao = new UserDaoImpl(); List<User> list = dao.findAllUser(); //将需要传递的数据 放置到request对象中 req.setAttribute("users", list); //list = req.getAttribute("user"); String path = "user/view"; //String path="/WEB-INF/view/users.jsp"; //request API 提供了 Servlet之间协作处理 //的功能, forward: 协作(请求)转发 RequestDispatcher rd = req.getRequestDispatcher(path); } }
注意这个 控制器 必须依赖 显示组件 才能工作
-
配置 web.xml
<servlet> <description></description> <display-name>ListAllServlet</display-name> <servlet-name>ListAllServlet</servlet-name> <servlet-class>controller.ListAllServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListAllServlet</servlet-name> <url-pattern>/user/listall</url-pattern> </servlet-mapping>
-
编写视图 ViewServlet
public class ViewServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //显示组件,只负责显示用户信息 //获得用户信息 List<User> users = (List<User>) req.getAttribute("users"); System.out.println("users"+users); resp.setContentType("text/html;charset=utf-8"); resp.setCharacterEncoding("utf-8"); PrintWriter out = resp.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<meta charset='utf-8'>"); out.println("</head>"); out.println("<body>"); out.println("<h1>全部用户</h1>"); out.println("<table>"); out.println(" <tr>"); out.println(" <td>编号</td>"); out.println(" <td>用户名</td>"); out.println(" </tr>"); for (User u : users) { out.println(" <tr>"); out.print(" <td>"); out.print(u.getId()); out.println(" </td>"); out.print(" <td>"); out.print(u.getUsername()); out.println(" </td>"); out.println(" </tr>"); } out.println("</table>"); out.println("</body>"); out.println("</html>"); } }
-
配置 web.xml
<servlet> <description></description> <display-name>ViewServlet</display-name> <servlet-name>ViewServlet</servlet-name> <servlet-class>view.ViewServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ViewServlet</servlet-name> <url-pattern>/user/view</url-pattern> </servlet-mapping>
测试
http://8080/servlet1/user/listall
JSP
JSP Java 推荐的视图组件,用于解决Servlet作为视图使用非常繁琐的问题,JSP按照HTML语法编写,在运行期间解释为Servlet工作:
编写JSP实现视图组件功能:
-
编写JSP实现视图组件功能:
<%@ page import="java.util.List,entity.User" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>用户列表</title> </head> <body> <h1>用户JSP</h1> <table> <tr> <td>编号</td> <td>用户名</td> </tr> <% //Java程序脚本 List<User> users = (List<User>)request.getAttribute("users"); for(User u: users){ %> <tr> <td><%=u.getId() %></td> <td><%=u.getUsername() %></td> </tr> <% } %> </table> </body> </html>
这里将JSP保存在 WEB-INF文件夹的目的是为了避免视图组件被用户之间访问出现异常信息。
-
重构控制器 LustServlet,更新视图组件:
... //转发到视图显示users数据 String path="/WEB-INF/view/users.jsp"; //request API 提供了 Servlet之间协作处理 //的功能,forward: 协作(请求)转发 RequestDispatcher rd = req.getRequestDispatcher(path); rd.forward(req,resp); ...
-
测试:
http://localhost:8080/servlet/user/listall
后续课程讲解详细的 JSP语法
- JSP 指令 <%@ %>
- JSP 脚本 <% ... %>
- JSP 表达式 <%=表达式%>
作业
- 实现课堂案例
- 利用 Servlet/JSP 配合实现 商品列表