1.Servlet简介
(1)Java Servlet是和平台无关的服务器端组件,它运行在Servlet容器中。Servlet容器负责Servlet和 客户的通信以及调用Servlet的方法,Servlet和客户的通信采用“请求/响应”的模式。
(2)Servlet可完成如下功能:创建并返回基于客户请求的动态HTML页面;创建可嵌入到现有HTML 页面中的部分HTML 页面(HTML 片段);与其它服务器资源(如数据库或基于Java的应用程序)进行通信。
2.Servlet的helloworld实现
首先,需要创建一个实现Servlet接口的实现类:public class HelloWorld implements Servlet
package com.zhaoliang.javaweb;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/*
* 如何创建Servlet?
*/
public class HelloServlet implements Servlet{
@Override
public void destroy() {
System.out.println("destroy");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("servlet config");
return null;
}
@Override
public String getServletInfo() {
System.out.println("servlet info");
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
System.out.println("init");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("service");
}
public HelloServlet(){
System.out.println("HelloServlet's constructor");
}
}
创建完成Servlet之后,我们需要在web.xml文件中配置和映射Servlet
<pre name="code" class="html"><?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">
<!-- 配置Servlet -->
<servlet>
<!-- Servlet的注册名 -->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet的全类名 -->
<servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class>
</servlet>
<!-- 映射Servlet -->
<servlet-mapping>
<!-- 与某一个Servlet的注册名一致 -->
<servlet-name>helloServlet</servlet-name>
<!-- 映射具体的访问路径:/代表当前项目的根目录 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
这样我们就可以在服务上运行Servlet了。
注:
1.Servlet容器:运行Servlet,JSP,Filter等软件环境
1)可以用来创建Servlet,并调用Servlet相关生命周期方法
2)JSP,Filter,Listener,Tag......
2.Servlet的生命周期方法:以下方法都是由Servlet容器进行调用
1)构造器(constructor):只被调用一次。只有第一次请求Servlet时,创建Servlet实例,调用构造器。这说明Servlet是单实例的(存在线程安全问题,不应创建全局变量)
2)init:只被调用一次。创建好实例后立即被调用,用于初始化Servlet。
3)service:被多次调用。每次请求都会调用service方法。实际用于响应请求。
4)destroy:只被调用一次。当前Servlet所在的WEB应用被卸载前调用,用于释放当前Servlet所占用的资源。
5)Servlet方法调用的过程:
(1)Servlet引擎检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
(2)装载并创建该Servlet的一个实例对象:调用该 Servlet 的构造器
(3)调用Servlet实例对象的init()方法。
(4)创建一个用于封装请求的ServletRequest对象和一个代表响应消息的ServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
(5)WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
3.load-on-startup参数
1)配置在<Servlet></Servlet>节点中
<servlet>
<!-- Servlet的注册名 -->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet的全类名 -->
<servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
2)作用:load-on-startup可以指定Servlet被创建的时机。若为负数,则在第一次请求时被创建。若为0或正数,则在当前WEB应用被Servlet容器加载时创建实例,且数值越小越早被创建。
4.<servlet-mapping></servlet-mapping>
1)同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
2)在Servlet映射到的URL中也可以使用 * 通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
<!-- 映射Servlet -->
<servlet-mapping>
<!-- 与某一个Servlet的注册名一致 -->
<servlet-name>helloServlet</servlet-name>
<!-- 映射具体的访问路径:/代表当前项目的根目录 -->
<url-pattern>/*</url-pattern>
</servlet-mapping>
或者
<!-- 映射Servlet -->
<servlet-mapping>
<!-- 与某一个Servlet的注册名一致 -->
<servlet-name>helloServlet</servlet-name>
<!-- 映射具体的访问路径:/代表当前项目的根目录 -->
<url-pattern>*.html</url-pattern>
</servlet-mapping>
5.ServletConfig:封装了Servlet配置信息,获取ServletContext对象(init方法中的参数)
1)配置Servlet初始化参数
<!-- 配置Servlet -->
<servlet>
<!-- Servlet的注册名 -->
<servlet-name>helloServlet</servlet-name>
<!-- Servlet的全类名 -->
<servlet-class>com.zhaoliang.javaweb.HelloServlet</servlet-class>
<!-- 配置Servlet初始化参数,该节点必须放在loa-on-startup节点之前 -->
<init-param>
<!-- 参数名 -->
<param-name>user</param-name>
<!-- 参数值 -->
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>1230</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
2)获取初始化参数
>getInitParameter(String name):返回String,获取指定参数名的初始化参数
>getInitParameterNames():返回
Enumeration
,返回参数名。
@Override
public void init(ServletConfig arg0) throws ServletException {
System.out.println("init");
String user = arg0.getInitParameter("user");
System.out.println("user:" + user);
System.out.println("========");
Enumeration names = arg0.getInitParameterNames();
while(names.hasMoreElements()){
String name = (String) names.nextElement();
System.out.println("name:" + name);
}
String servletName = arg0.getServletName();
System.out.println("========");
System.out.println("servletname : " + servletName);
}
3)ServletContext对象
(1)可以有 ServletConfig 的 getServletContext 方法获得
(2)该对象代表当前WEB应用,可以认为ServletContext是WEB应用的一个大管家,可以获取当前WEB应用的各个信息。
①获取当前WEB应用的初始化参数
首先,需要设置WEB应用的初始化参数(注意:<context-param>与<init-param>的区别:<context-param>是全局的初始化参数,所有的Servlet都可以访问获取,而<init-param>是局部的初始化参数,只有特定的(HelloServlet)可以获取
<!-- 配置当前WEB应用初始化参数(全局的,所有的Servlet都可以获取 -->
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.driver</param-value>
</context-param>
<context-param>
<param-name>jdbcURL</param-name>
<param-value>jdbc:mysql///zhaoliang</param-value>
</context-param>
方法:
>getInitParameter(String name):返回String,获取指定参数名的初始化参数
>getInitParameterNames():返回
Enumeration
,返回参数名。
@Override
public void init(ServletConfig arg0) throws ServletException {
System.out.println("init");
ServletContext servletContext = arg0.getServletContext();
String driver = servletContext.getInitParameter("driver");
System.out.println("driver : " + driver);
System.out.println("=============");
Enumeration<String> names = servletContext.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = servletContext.getInitParameter(name);
System.out.println("name :" + name + "--> value : " + value);
}
}
②获取当前 WEB 应用的某一个文件在服务器上的绝对路径(必须是在webContent文件夹下),而不是部署前的路径
getRealPath(String path)
③获取当前 WEB 应用的名称
getContentPath()
getResourceAsStream(String path) : path / 相对于当前应用的根目录
⑤和Attribute相关的四个方法
getAttribute(String name) ,getAttributeNames(),removeAttribute(String name),setAttribute(String name,Object object)
@Override
public void init(ServletConfig arg0) throws ServletException {
System.out.println("init");
ServletContext servletContext = arg0.getServletContext();
String realPath = servletContext.getRealPath("hello.jsp");
System.out.println("realPath :" + realPath);
String contextPath = servletContext.getContextPath();
System.out.println("contextPath :" + contextPath);
InputStream is = servletContext.getResourceAsStream("/hello.jsp");
System.out.println("stream :" + is);
}
3.GET 和POST
1.使用 GET 方式传递参数
1)在浏览器地址栏中输入某个URL地址或单击网页上的一个超链接时,浏览器发出的HTTP请求消息的请求方式为GET。
2)如果网页中的<form>表单元素的method属性被设置为了“GET”,浏览器提交这个FORM表单时生成的HTTP请求消息的请求方式也为GET。
3)使用GET请求方式给WEB服务器传递参数的格式:
http://www.lampbrother.net/counter.jsp?name=lc&password=123
4)使用GET方式传送的数据量一般限制在1KB以下。
2.使用 POST 方式传递参数
1)POST请求方式主要用于向WEB服务器端程序提交FORM表单中的数据。 form 表单的 method 设置为 POST
2)POST方式将各个表单字段元素及其数据作为HTTP消息的实体内容发送给WEB服务器,传送的数据量要比使用GET方式传送的数据量大得多。
3)POST请求消息的格式:
POST /counter.jsp HTTP/1.1
referer: http://localhost:8080/Register.html
content-type: application/x-www-form-urlencoded
host: localhost:8080
content-length: 43
name=zhangsan&password=123
3.如何在Servlet中获取请求参数
1)Servlet的 service() 用于应答请求,每次请求都会调用 service() 方法
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
>ServletRequest:封装了请求信息,从中可以获取任何请求信息
>ServletResponse:封装了响应信息,如果想给用户什么响应,可以通过ServletResponse的相关方法实现。
这两个接口的实现类都是服务器给予实现的,并在服务器调用 service 方法时传入
2)ServletRequest:封装了请求信息,从中可以获取任何请求信息
(1)获取请求参数
>String getParameter(String name):根据请求参数的名字,返回参数值
>String[] getParameterValues(String name):根据请求参数名字,返回一组参数值(多选checkbox)
>Enumeration getParameterNames():类似于ServletConfig(ServletContext)的 getInitParameterNames()
>Map getParameterMap():返回请求参数的键/值对,键-->参数名 值-->String数组类型
页面信息(login.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="LoginServlet" method="post">
user:<input type="text" name="user"/>
password:<input type="password" name="password"/>
<br><br>
interesting:
<input type="checkbox" name="interesting" value="reading"/>reading
<input type="checkbox" name="interesting" value="watchingTV"/>watchingTV
<input type="checkbox" name="interesting" value="sport"/>sport
<input type="checkbox" name="interesting" value="game"/>game
<br><br>
<input type="submit" value="submit"/>
</form>
</body>
</html>
Servlet信息(LoginServlet)
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class LoginServlet implements Servlet {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("请求来了...");
System.out.println();
String user = request.getParameter("user");
String password = request.getParameter("password");
System.out.println("!!!" + user + "," + password);
System.out.println();
String[] interestings = request.getParameterValues("interesting");
for(String interest:interestings){
System.out.println("@@@" + interest);
}
System.out.println();
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = request.getParameter(name);
System.out.println("###" + name + "," + value);
}
System.out.println();
Map<String,String[]> paraMap = request.getParameterMap();
for(Map.Entry<String, String[]> entry :paraMap.entrySet()){
System.out.println("$$$" + entry.getKey() + ":" + Arrays.asList(entry.getValue()));
}
}
}
(2)HttpServletRequest:是ServletRequest的子接口,针对HTTP所定义,里面包含了大量获取HTTP请求信息的相关方法。
> HttpServletRequest httpServletRequest = (HttpServletRequest) request;
> getRequestURI():获取请求URL
> getMethod():获取请求方法
>getQueryString():获取GET请求 ? 后的字符串
>getServletPath():获取Servlet的映射路径
>和Attribute相关的方法:
3)ServletResponse:封装了响应信息,如果想给用户什么响应,可以通过ServletResponse的相关方法实现
(1)getWriter():返回 PrintWriter 对象,调用该对象的 print() 方法,将print()中的内容直接打印到客户的浏览器上。
(2)getContentType(String contentTypeNmae):设置响应内容类型
(3)getOutputStream():返回OutputStream对象,下载图片,word文档时可以用到
(4)void sendRedirect(String location):请求重定向。此方法为HttpServletResponse中定义(HttpServletResponse httpServletResponse = (HttpServletResponse) response;
综合练习:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!--
在web.xml文件中设置两个WEB应用初始化参数:user,password。
定义一个login.html,里边定义两个请求字段:user,password,发送请求到loginServlet
创建LoginServlet,在其中获取请求参数user,password,对比web.xml中的参数是否一致
若一致,输出hello XXX;若不一致,输出 sorry XXX
-->
<form action="loginServlet" method="post">
user:<input type="text" name="user"/>
password:<input type="password" name="password"/>
<input type="submit" value="submit"/>
</form>
</body>
</html>
<?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>day_02</display-name>
<context-param>
<param-name>user</param-name>
<param-value>Tom</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</context-param>
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.zhaoliang.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
</web-app>
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class LoginServlet implements Servlet {
private ServletContext servletContext = null;
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
String userClient = request.getParameter("user");
String passwordClient = request.getParameter("password");
String userService = null;
String passwordService = null;
if(servletContext != null){
userService = servletContext.getInitParameter("user");
passwordService = servletContext.getInitParameter("password");
}
PrintWriter printWriter = response.getWriter();
if(userService.equals(userClient) && passwordService.equals(passwordClient)){
printWriter.println("hello: " + userService);
}else{
printWriter.println("sory: " + userClient);
}
}
@Override
public void destroy() {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
servletContext = servletConfig.getServletContext();
}
}
4.GenericServlet
1)是一个Servlet,是Servlet接口和ServletConfig接口的实现类,但是一个抽象类,其中service方法为抽象方法
2)如果新建的Servlet程序直接继承GenericServlet,会使开发变得很简洁
3)具体实现
(1)在 GenericServlet 中,定义一个ServletConfig类型的对象,并在init(ServletConfig arg0)中为其初始化
(2)利用ServletConfig 成员变量的方法实现了ServletConfig接口的方法
(3)还定义了一个init()方法,在init(ServletConfig)方法中对其进行调用,子类可以直接覆盖init()方法,在其中实现对Servlet的初始化
(4)不建议直接覆盖init(ServletConfig),如果忘记编写super(ServletConfig),而且还用了ServletConfig接口方法,会出现空指针异常。
(5)init()不是Servlet的生命周期方法,而init(ServletConfig)才是生命周期方法
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public abstract class MyGenericServlet implements Servlet,ServletConfig {
/*
* Servlet接口的方法实现
*/
@Override
public void destroy() {}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public String getServletInfo() {
return null;
}
private ServletConfig servletConfig;
@Override
public void init(ServletConfig arg0) throws ServletException {
this.servletConfig = arg0;
init();
}
//重载初始化方法,用户可以自行初始化,而没有空指针错误
public void init() throws ServletException {}
@Override
public abstract void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException;
/*
* ServletConfig接口方法的实现
*/
@Override
public String getInitParameter(String arg0) {
return servletConfig.getInitParameter(arg0);
}
@Override
public Enumeration getInitParameterNames() {
return servletConfig.getInitParameterNames();
}
@Override
public ServletContext getServletContext() {
return servletConfig.getServletContext();
}
@Override
public String getServletName() {
return servletConfig.getServletName();
}
}
5.HttpServlet
1)是一个Servlet,继承自GenericServlet,针对于HTTP协议定制
2)在service方法中直接把ServletRequest和ServletResponse转为HttpServletRequest和HttpServletResponse,并调用了重载的service(HttpServletRequest,HttpServletResponse)。在service(HttpServletRequest,HttpServletResponse)中获取了请求方式 request.getMethod(),根据请求方式创建了doXXX(xxx为具体的请求方式,比如GET,POST)方法。
3)实际开发中,直接继承HttpServlet,根据请求方式调用doXXX方法
4)直接有针性的覆盖doXXX方法,直接使用HttpServletRequest和HttpServletResponse对象不需要强转。
5)Servlet的关系图
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import sun.awt.HToolkit;
public class MyHttpServlet extends MyGenericServlet {
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) arg0;
response = (HttpServletResponse) arg1;
} catch (ClassCastException e) {
throw new ServletException("non-Http request or response");
}
service(request, response);
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求方式
String method = request.getMethod();
//2.根据请求方式在创建对应的处理方法
if("GET".equalsIgnoreCase(method)){
doGet(request,response);
}
if("POST".equalsIgnoreCase(method)){
doPost(request,response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
}
}
6.综合练习
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!--
在web.xml文件中设置两个WEB应用初始化参数:user,password。
定义一个login.html,里边定义两个请求字段:user,password,发送请求到loginServlet
创建LoginServlet,在其中获取请求参数user,password,对比web.xml中的参数是否一致
若一致,输出hello XXX;若不一致,输出 sorry XXX
-->
<form action="loginServlet" method="post">
user:<input type="text" name="user"/>
password:<input type="password" name="password"/>
<input type="submit" value="submit"/>
</form>
</body>
</html>
<?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>day_02</display-name>
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.zhaoliang.servlet.LoginServlet3</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
</web-app>
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 java.text.Format;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.Response;
public class LoginServlet3 extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("user");
String password = req.getParameter("password");
Connection connection = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "select count(id) from test_users where name = ?"
+ "and password = ?";
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql:///zhaoliang";
String user = "root";
String password2 = "123456";
connection = DriverManager.getConnection(url, user, password2);
ps = connection.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
PrintWriter pWriter = resp.getWriter();
if(rs.next()){
int count = rs.getInt(1);
pWriter.println(count);
if(count > 0){
pWriter.println("hello : " + username);
}else{
pWriter.println("sorry : " + username);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}