Servlet是用Java编写的服务器端程序,是Sun公司提供的一套接口规范,用来处理基于HTTP协议的客户端请求,响应给浏览器的动态资源。
下面通过做个简单的用户名提交网页,了解下Servlet的工作流程。
1.引入Servlet-api.jar
2.实现Servlet
public class DemoServlet extends HttpServlet {
//Servlet是单列模式,只有一个对象
//此对象是根据web.xml的配置信息通过反射生成的
//因此一定要保证Servlet 的实现类有一个 public 修饰且无参的构造函数
//因为反射生成类,需要的是无参公开的构造函数
public DemoServlet() {
}
//用来初始化当前Servlet,只在服务器启动时调用一次
@Override
public void init(ServletConfig config) throws ServletException {
}
//每次连接服务器都会调用
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取用户提交的用户名
//参数name对应,网页表单里name的值
String name = req.getParameter("name");
System.out.println("用户提交的用户名为:" + name);
}
//销毁,只有在停止服务器时才会调用,因此一般不将销毁资源写在这里
@Override
public void destroy() {
}
}
3.web.xml中配置Servlet映射
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<!-- 3. 为下面的映射定义一个可找到的名称 -->
<servlet-name>DemoServlet</servlet-name>
<!-- 4. Tomcat通过包找到用户写好的Servlet -->
<servlet-class>com.servlet.DemoServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 2.根据用户自定义的servlet名称找到servlet -->
<servlet-name>DemoServlet</servlet-name>
<!-- 1.表单提交时,action对应的servlet -->
<url-pattern>/demo</url-pattern>
</servlet-mapping>
</web-app>
2.在index.jsp中编写界面
<html>
<head>
<title>Demo</title>
</head>
<body>
<%-- action="处理此请求的servlet"--%>
<form action="/demo" method="get">
<input type="text" placeholder="用户名" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
Servlet的配置
1.完全匹配
请求必须完全匹配设定的url-pattern
<servlet-mapping>
<servlet-name>DemoServlet</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
2.目录匹配
请求(/aa/bb/ccc)都会检索到该目录指向的Servlet
<url-pattern>/aa/bb/cc/*</url-pattern>
3.扩展名匹配
后缀名为.demo的就能访问
<url-pattern>*.demo</url-pattern>
4.缺省配置
当请求的资源地址,所有的Servlet都不匹配时,就由缺省配置的Servlet处理
<url-pattern>/</url-pattern>
其他细节
1. 一个Servlet可以有多个<url-pattern>
2.非常消耗资源的初始化操作,要放到服务器启动时
<servlet>
<servlet-name>ServletResponseTest</servlet-name>
<servlet-class>com.w.servlet.ServletResponseTest</servlet-class>
<!-- 数字越小越先执行初始化 -->
<load-on-startup>0</load-on-startup>
</servlet>
Servlet使用注解配置映射信息
Serlvet3.0引入了注解的方式配置映射信息
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
注意:一定要在配置清单中添加
metadata-complete="false">
</web-app>
@WebServlet(value = "/demo",
loadOnStartup = 1,
initParams = { @WebInitParam(name = "", value = "") }
)
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String name = req.getParameter("name");
System.out.println("用户提交的用户名为:" + name);
}
}
Servlet相关API
1.ServletConfig(javax.servlet.ServletConfig)
当Servlet中存在硬编码,要将其配置到 web.xml 中,以提高文件可维护性。
将配置的信息抽取出来放到web.xml文件中
<servlet>
<servlet-class>com.w.run.HellowServlet</servlet-class>
<servlet-name>HelloServlet</servlet-name>
<!-- 初始化参数配置 -->
<init-param>
<!-- 参数名称 -->
<param-name>encoding</param-name>
<!-- 参数值 -->
<param-value>UTF-8</param-value>
</init-param>
</servlet>
public class DemoServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
ServletConfig servletConfig = getServletConfig();//获取配置信息类
String encoding = config.getInitParameter("encoding");
System.out.println(encoding);
}
}
Config 其他API
public class DemoServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
//获取全部初始化参数
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
System.out.println(initParameterNames.nextElement());
}
//获取当前servlet的名称
String servletName = config.getServletName();
System.out.println(servletName);
//获取当前servlet的上下文
ServletContext servletContext = config.getServletContext();
}
}
2.ServletContext
ServletContext对象,代表一个Web应用,封装了该Web应用的信息,该对象在服务器启动时,创建,该Web应用销毁时,销毁。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = getServletContext();
context.setAttribute("key", "Value");
context.getAttribute("key");
context.removeAttribute("key");
}
ServletContext重要API
配置全局参数所有Servlet中都能获取
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<!-- 全局初始化参数,在所有Servlet中都能获取 -->
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
</web-app>
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = getServletContext();
//获取Web.xml中配置的全局参数
context.getInitParameter("encoding");
//获取Web应用中任何资源的绝对路径
context.getRealPath("path");
}
Servlet的Request,Response
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
}
}
1.ServletRequest(子接口实现:HttpServletRequest)
用来处理基于HTTP协议的请求,其对象在每次请求时创建,响应结束后销毁。
Request常用的API
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
/**
* 以下是获取用户提交的请求里参数的方法
*/
req.getParameter("name"); //获取指定名称的参数的值
req.getParameterMap(); //获取所有请求参数并封装到一个Map
req.getParameterNames(); //获取所有请求参数的名称
req.getParameterValues(""); //获取多个表单的值,CheckBox的
//Request的域对象,传递数据
req.setAttribute("key","value");
req.getAttribute("key");
req.removeAttribute("key");
req.getContextPath(); //获取上下文路径
req.getHeader("User-Agent"); //获取指定名称的请求头信息
req.getMethod(); //获取请求方式
req.getRequestURI(); //获取资源的名称
req.getRequestURL(); //获取请求资源的全路径
}
BeanUtils框架的使用
表单提交的多个参数,往往需要封装成JavaBean,用传统写法太过繁琐,这就需要借助框架帮助。
try {
/**
* BeanUtils工作原理:将Map中的数据,根据Key与实体的属性的对应关系封装
* 只要Key的名字与实体的属性名字一样就自动封装到实体中
*/
User user = new User();
BeanUtils.populate(user, req.getParameterMap());
} catch (Exception e) {
e.printStackTrace();
}
2.ServletResponse(子接口实现:HttpServletResponse)
用来处理基于HTTP协议的请求后的响应信息。
Response常用API
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//Response获得流不需要手动关闭,Tomcat会帮助我们关闭
//getWrite()和getOutputStream(); 不允许同时调用,这里只做演示
PrintWriter writer = resp.getWriter();
ServletOutputStream outs = resp.getOutputStream();
resp.setStatus(201); //设置状态码
resp.setHeader("key", "value"); //设置响应头
resp.addHeader("key", "value"); //添加响应头
}
Servlet请求响应时,中文乱码问题
Tomcat默认使用的ISO-8859-1的方式处理请求参数,不适合中文的编码。
MIME类型(文件格式)"text/html"的响应问题。
1.解决办法
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
2..用解码编码的方式
byte[] bytes = name.getBytes("ISO-8859-1"); //解码
name = new String(bytes, "UTF-8"); //编码
3.. 修改Tomcat配置,但只支持get请求。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="utf-8"/>
4.在获取请求参数之前设置请求编码,只支持post请求。
req.setCharacterEncoding("UTF-8");
Response响应流程
1.客户端发送请求到服务端Tomcat
2.服务端Tomcat引擎发送Request请求
3.服务端响应的数据会存到Response缓冲区
4.Tomcat引擎取出Response缓冲区的内容,与引擎自己添加的信息组装成一个Http响应给客户端。