教程假定您已经了解了 JDBC 应用程序的工作方式。在您开始学习 Servlet 数据库访问之前,请确保您已经有适当的 JDBC 环境设置和数据库。
从基本概念下手,让我们来创建一个简单的表,并在表中创建几条记录。
创建数据库表
在测试数据库 TEST 中创建 Employees 表,请按以下步骤进行:
步骤 1:
打开命令行提示符(Command Prompt),并更改进入到安装目录,如下所示:
C:\> C:\>cd Program Files\MySQL\bin C:\Program Files\MySQL\bin>
步骤 2:
登录到数据库,如下所示:
C:\Program Files\MySQL\bin>mysql -u root -p Enter password: ******** mysql>
步骤 3:
在测试数据库 TEST 中创建 Employee 表,如下所示:
mysql> use TEST; mysql> create table Employees ( id int not null, age int not null, first varchar (255), last varchar (255) ); Query OK, 0 rows affected (0.08 sec) mysql>
创建数据记录
最后,在 Employee 表中创建几条记录,如下所示:
mysql> INSERT INTO Employees VALUES (100, 18, 'Zara', 'Ali'); Query OK, 1 row affected (0.05 sec) mysql> INSERT INTO Employees VALUES (101, 25, 'Mahnaz', 'Fatma'); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO Employees VALUES (102, 30, 'Zaid', 'Khan'); Query OK, 1 row affected (0.00 sec) mysql> INSERT INTO Employees VALUES (103, 28, 'Sumit', 'Mittal'); Query OK, 1 row affected (0.00 sec) mysql>
访问数据库
下面的实例演示了如何使用 Servlet 访问 TEST 数据库。
// 加载必需的库 import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import java.sql.*; public class DatabaseAccess extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // JDBC 驱动器名称和数据库的 URL static final String JDBC_DRIVER="com.mysql.jdbc.Driver"; static final String DB_URL="jdbc:mysql://localhost/TEST"; // 数据库的用户名与密码,需要根据自己的设置 static final String USER = "root"; static final String PASS = "password"; // 设置响应内容类型 response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "数据库结果"; String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n"; out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n" + "<h1 align=\"center\">" + title + "</h1>\n"); try{ // 注册 JDBC 驱动器 Class.forName("com.mysql.jdbc.Driver"); // 打开一个连接 Connection conn = DriverManager.getConnection(DB_URL,USER,PASS); // 执行 SQL 查询 Statement stmt = conn.createStatement(); String sql; sql = "SELECT id, first, last, age FROM Employees"; ResultSet rs = stmt.executeQuery(sql); // 展开结果集数据库 while(rs.next()){ // 通过字段检索 int id = rs.getInt("id"); int age = rs.getInt("age"); String first = rs.getString("first"); String last = rs.getString("last"); // 输出数据 out.println("ID: " + id + "<br>"); out.println(", Age: " + age + "<br>"); out.println(", First: " + first + "<br>"); out.println(", Last: " + last + "<br>"); } out.println("</body></html>"); // 完成后关闭 rs.close(); stmt.close(); conn.close(); }catch(SQLException se){ // 处理 JDBC 错误 se.printStackTrace(); }catch(Exception e){ // 处理 Class.forName 错误 e.printStackTrace(); }finally{ // 最后是用于关闭资源的块 try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ } try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); } } } }
现在让我们来编译上面的 Servlet,并在 web.xml 文件中创建以下条目:
.... <servlet> <servlet-name>DatabaseAccess</servlet-name> <servlet-class>DatabaseAccess</servlet-class> </servlet> <servlet-mapping> <servlet-name>DatabaseAccess</servlet-name> <url-pattern>/DatabaseAccess</url-pattern> </servlet-mapping> ....
现在调用这个 Servlet,输入链接:http://localhost:8080/DatabaseAccess,将显示以下响应结果:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>spring_mvc</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
eb框架是开发者在使用某种语言编写Web应用服务端项目时关于架构的最佳实践。很多Web框架是从实际的Web项目抽取出来的,仅和Web的请求和响应处理有关,形成一个基础,在开发别的应用项目的时候则可以从这个剥离出来的基础做起,让开发者更关注更具体的业务问题,而不是Web的请求和响应的控制。
框架很多,但套路基本类似,帮你隐藏很多关于 HTTP 协议细节内容,专注功能开发。
但对一个初学者来说,过早的接触框架往往是事倍功半!同样一个问题,换一种框架你可能需要从头开始研究。
下面是针对初学 Java 开发 Web 过程一些个人见解和思路,高手可略过。
有良好的 Java 语言编程基础,这是必须的,在讨论 Web 开发技术时提了一个 Java 编程基础的问题会被鄙视的。
选择一个你喜爱的Servlet容器,或者说大一点就是应用服务器,推荐 Tomcat 、Resin 或者 Jetty 这些轻量级的产品。这三个产品下载 zip 包解压后就可以用了。如果你不熟悉 Tomcat 的话请不要使用 exe 版本的 Tomcat,那会徒增很多烦恼。
把应用服务器启动起来并能访问到其默认的页面为准。
关于开发工具:不推荐使用 MyEclipse 和 Eclipse 的 JEE 版本,徒增烦恼、运行缓慢而且还让你无法了解 Web 项目的结构。普通的 Eclipse 或者你喜欢的开发工具就足够了,能支持普通 Java 项目开发即可。
为了方便,我做了一个最基本的Java 项目 —— ServletDemo.zip(评论区见链接) ,你可将它导入到 Eclipse 里就是一个完整的、最简单的 Web 项目。
然后将下面 XML 内容替换 Tomcat 下的 conf/server.xml 文件:
<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost">
<Context path="" docBase="D:\WORKDIR\ServletDemo\webapp" reloadable="true"/>
</Host>
</Engine>
</Service>
</Server>
其中 D:\WORKDIR\ServletDemo 替换为你导入的项目路径,再次启动 Tomcat 后在浏览器打开 http://localhost:8080/hello 便可看到 Hello World 的输出信息。
好了,我已经把环境搭起来了,接下来该干嘛呢?
前面的步骤为的是搭建一个测试的环境,然后让你了解一个最基本的 Java Web 项目的结构。
一个最基本的 Java Web 项目所需的 jar 包只需要一个 servlet-api.jar ,这个 jar 包中的类大部分都是接口,还有一些工具类,共有 2 个包,分别是 javax.servlet 和 javax.servlet.http。我把这个jar包放到了 webapp 目录外的一个独立 packages 文件夹里,这是因为所有的 Servlet 容器都带有这个包,你无需再放到Web项目里,我们放到这里只不过是编译的需要,运行是不需要的。如果你硬是把 servlet-api.jar 放到 webapp/WEB-INF/lib 目录下,那么 Tomcat 启动时还会报一个警告信息。
Java Web 项目还需要一个非常重要的配置文件 web.xml ,在这个项目中已经被我最小化了,只保留有用的信息:
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<servlet>
<servlet-name>hello_world</servlet-name>
<servlet-class>demo.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello_world</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
每个 servlet 都必须在 web.xml 中定义并进行 URL 映射配置,早期 Java 开发 Web 在没有框架满天飞的时候,这个文件会定义了大量的 servlet,或者有人为了省事干脆来一个 /servlet/* 来通过类名直接调用 Servlet。
Servlet 规范里还有另外一个非常重要而且非常有用的接口那就是 Filter 过滤器。
下面是一个最简单的 Filter 类以及相应的定义方法:
package demo;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class HelloFilter implements Filter {
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("Filter 初始化");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
System.out.println("拦截 URI="+request.getRequestURI());
chain.doFilter(req, res);
}
@Override
public void destroy() {
System.out.println("Filter 结束");
}
}
在 web.xml 中的配置必须放在 Servlet 的前面:
访问 http://localhost:8080/hello 时看看 Tomcat 控制台有何输出信息。
Servlet 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了,J2EE 的其他方面的内容择需采用。而 Servlet 规范你需要掌握的就是 servlet 和 filter 这两项技术。绝大多数框架不是基于 servlet 就是基于 filter,如果它要在 Servlet 容器上运行,就永远也脱离不开这个模型。
为什么 Servlet 规范会有两个包,javax.servlet 和 javax.servlet.http ,早先设计该规范的人认为 Servlet 是一种服务模型,不一定是依赖某种网络协议之上,因此就抽象出了一个 javax.servlet ,同时在提供一个基于 HTTP 协议上的接口扩展。但是从实际运行这么多年来看,似乎没有发现有在其他协议上实现的 Servlet 技术。
javax.servlet 和 javax.servlet.http 这两个包总共加起来也不过是三十四个接口和类。你需要通过 J2EE 的 JavaDoc 文档 熟知每个类和接口的具体意思。特别是下面几个接口必须熟知每个方法的意思和用途:
再次强调 HttpServletRequest 和 HttpServletResponse 这两个接口更应该是烂熟于心。
如果你从字面上无法理解某个方法的意思,你可以在前面那个项目的基础上做实验看看其输出,再不行你可以到讨论区提问,这样的提问非常明确,很多人都可以帮到你。
为什么我这么强调 HttpServletRequest 和 HttpServletResponse 这两个接口,因为 Web 开发是离不开 HTTP 协议的,而 Servlet 规范其实就是对 HTTP 协议做面向对象的封装,HTTP协议中的请求和响应就是对应了 HttpServletRequest 和 HttpServletResponse 这两个接口。
你可以通过 HttpServletRequest 来获取所有请求相关的信息,包括 URI、Cookie、Header、请求参数等等,别无它路。因此当你使用某个框架时,你想获取HTTP请求的相关信息,只要拿到 HttpServletRequest 实例即可。
而 HttpServletResponse接口是用来生产 HTTP 回应,包含 Cookie、Header 以及回应的内容等等。
HTTP 协议里是没有关于 Session 会话的定义,Session 是各种编程语言根据 HTTP 协议的无状态这种特点而产生的。其实现无非就是服务器端的一个哈希表,哈希表的Key就是传递给浏览器的名为 jsessionid 的 Cookie 值。
当需要将某个值保存到 session 时,容器会执行如下几步:
a. 获取 jsessionid 值,没有的话就生成一个,也就是 request.getSession() 这个方法b. 拿到的 HttpSession 对象实例就相当于一个哈希表,你可以往哈希表里存放数据(setAttribute)c. 你也可以通过 getAttribute 来获取某个值
而这个名为 jsessionid 的 Cookie 在浏览器关闭时会自动删除。把 Cookie 的 MaxAge 值设为 -1 就能达到浏览器关闭自动删除的效果。
首先我已经不用 JSP 很多年了,现在一直是使用 Velocity 模板引擎。
任何一个 JSP 页面在执行的时候都会编译成一个 Servlet 类文件,如果是 Tomcat 的话,这些生成的 java 文件会放置在 {TOMCAT}/work 目录下对应项目的子目录中,例如 Tomcat 生成的类文件如下:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.*;
public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List<String> _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.List<String> getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
public void _jspService(final HttpServletRequest request, final HttpServletResponse response)
throws java.io.IOException, ServletException {
final PageContext pageContext;
HttpSession session = null;
final ServletContext application;
final ServletConfig config;
JspWriter out = null;
final Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=utf-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("<html>\r\n");
out.write(" <title>Test</title>\r\n");
out.write(" <style>\r\n");
out.write(" </style> \r\n");
out.write(" <body>\r\n");
out.write("<h1>Test Demo (oschina)</h1>\r\n");
out.write("<table cellspacing=\"1\" cellpadding=\"5\">\r\n");
Enumeration Names=request.getHeaderNames();
while(Names.hasMoreElements())
{String name=(String)Names.nextElement();
String value=request.getHeader(name);
out.write("\r\n");
out.write(" <tr>\r\n");
out.write(" <td>");
out.print(name);
out.write("</td>\r\n");
out.write(" <td>");
out.print(value);
out.write("</td>\r\n");
out.write(" \r\n");
out.write(" </tr>\r\n");
out.write(" ");
}
out.write("\r\n");
out.write("</table>\r\n");
out.write(" </body>\r\n");
out.write("</html>");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
在 servlet 中有一个包 javax.servlet.jsp 是跟 JSP 相关的一些接口规范定义。JSP 比 Servlet 方便的地方在于可直接修改立即生效,不像 Servlet 修改后必须重启容器才能生效。
因此 JSP 适合用来做视图,而 Servlet 则适合做控制层。
7. 总结
罗哩罗嗦一大堆,归纳一下就是下面几点:
等你真的掌握了 Servlet 规范再去看框架,便会觉得一些都小菜。总之一点:不要被框架牵着鼻子走,框架是你的工具,它应该听你的!
*请认真填写需求信息,我们会在24小时内与您取得联系。