Servlet,全称Server Applet服务器端小程序,Servlet指的是必需运行在服务器端的Java小程序,狭义上讲,Servlet指的是javaEE提供的一个接口;广义上讲,所有实现了Servlet接口的java类,都可以被称为Servlet.
|-Servlet ->顶级接口
|- GenericServlet–>直接实现Servlet接口的抽象类
|-HttpServlet–>继承GenericServlet的抽象类.
public class HelloServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("HelloServlet执行了...");
}
}
<?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_4_0.xsd"
version="4.0">
<!--配置Servlet-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.bupt.HelloServlet</servlet-class>
</servlet>
<!--配置Servlet和路径之间的映射关系-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern><!--精确匹配/hello-->
<url-pattern>*.css</url-pattern><!--匹配以.css结尾的所有路径-->
<url-pattern>/bupt/*</url-pattern><!--匹配/bupt/下的所有路径-->
<url-pattern>/</url-pattern><!--除了.jsp的路径-->
<url-pattern>/*</url-pattern><!--所有路径-->
</servlet-mapping>
生命周期指的是一个对象从创建到消亡的过程,就Servlet而言,生命周期可以被分为四个阶段,分别是:
public class DemoServlet extends HttpServlet {
public DemoServlet() {
System.out.println("[1] 实例化");
}
@Override
public void init() throws ServletException {
System.out.println("[2] 初始化");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("[3] 提供服务...");
}
@Override
public void destroy() {
System.out.println("[4] 销毁");
}
}
<?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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>Demo</servlet-name>
<servlet-class>com.bupt.DemoServlet</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Demo</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
</web-app>
默认情况下,Servlet就是一种懒汉式单例,第一次使用时进行实例化和初始化,可以在web.xml配置文件中的< servlet>标签中加入< load-on-startup>修改为饿汉式单例.
HTML+Servlet+MyBatis+MySQL:
获取请求实体:
// 获取前台传递的用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
发送响应信息(输出流)
// 向页面输出信息, 响应
resp.getWriter().print("failed!");
resp.getWriter().print("
");
resp.getWriter().print("please try again!");
是service方法的第一个参数,HttpServletRequest,是一个接口,继承了父接口ServletRequest,该对象由Servlet容器创建(Tomcat),然后传递给service方法使用,用于为Servlet提供客户端发送请求的信息.
/**
* 获取请求行信息
*
* @param req
*/
private void getReqLine(HttpServletRequest req) {
System.out.println("协议版本号: " + req.getProtocol());
System.out.println("请求方式: " + req.getMethod());
System.out.println("url: " + req.getRequestURL());
System.out.println("uri: " + req.getRequestURI());
System.out.println("path: " + req.getServletPath());
System.out.println("协议名: " + req.getScheme());
}
/**
* 获取请求头信息
* @param req
*/
private void getReqHeader(HttpServletRequest req) {
String userAgent = req.getHeader("User-Agent");
System.out.println("userAgent: " + userAgent);
Enumeration<String> names = req.getHeaderNames();
while(names.hasMoreElements()) {
String name = names.nextElement();
System.out.println(name + ": " + req.getHeader(name));
}
}
/**
* 获取请求实体
*
* @param req
*/
private void getReqEntity(HttpServletRequest req) {
String username = req.getParameter("username");
String[] hobs = req.getParameterValues("hob");
System.out.println("username = " + username);
System.out.println("hobs = " + Arrays.toString(hobs));
}
/**
* 获取请求其他信息
*
* @param req
*/
private void getReqOther(HttpServletRequest req) {
System.out.println("服务器IP: " + req.getLocalAddr());
System.out.println("服务器端口号: " + req.getLocalPort());
System.out.println("客户端IP: " + req.getRemoteAddr());
System.out.println("客户端端口号: " + req.getRemotePort());
System.out.println("上下文(项目)路径: " + req.getContextPath());
System.out.println("真实路径: " + req.getRealPath("/upload"));
}
响应对象是service方法的第二个参数, HttpServletResponse, 是一个接口, 继承了父接口ServletResponse. 该对象由Servlet容器创建, 传递service方法使用, 用来帮助程序员对客户端的请求做出响应. 主要针对响应头和响应实体进行操作.
public class RespServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应头信息
// Content-Type设置响应内容的格式
// resp.setHeader("Content-Type", "text/html;charset=UTF-8");
resp.setContentType("text/html;charset=UTF-8");
resp.setHeader("demo", "mouse"); // 同名会覆盖
resp.addHeader("demo", "keyboard"); // 同名不会覆盖
resp.addHeader("demo", "screen");
// 设置响应实体
resp.getWriter().print("哈哈哈!
");
}
}
乱码问题的根本原因是编码格式不统一造成的. 常见的编码方式:
<!--告知浏览器使用哪种编码方式解析内容-->
<meta charset="UTF-8"> HTML4
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">HTML5
接收参数前设置编码格式为UTF-8
// 解决post请求乱码问题, 设置接收参数时使用的编码方式为UTF-8
req.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
需要手动转换和tomcat的版本有关(7及以前的版本)
String username = req.getParameter("username");
// 解决get乱码, 需要先使用ISO-8859-1解码为字节数组, 然后再重新使用UTF-8编码为字符串
byte[] bytes = username.getBytes("ISO-8859-1");
username = new String(bytes, "UTF-8");
// 设置响应头, 解决响应乱码
resp.setContentType("text/html;charset=UTF-8");
// 响应到客户端浏览器
resp.getWriter().print(username);
页面跳转指的是从一个位置跳转到另一个位置, 常用于Servlet之间的调用, 或者页面的显示. 在Servlet中, 有两种跳转方式: 请求转换和响应重定向.
不管跳转几个位置, 客户端只发送一次请求, 所有的跳转都是借助转发器实现的.
public class Demo1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("第一个Servlet被调用...");
System.out.println("demo1: " + req.getParameter("name"));
// 请求转发的实现, 通过请求对象实现的
req.getRequestDispatcher("demo2").forward(req, resp);
}
}
重定向时多次请求, 都是由客户端发起的.
public class Test1Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("[重定向] 第一个Servlet被调用...");
System.out.println("test1: " + req.getParameter("name"));
// 重定向到第二个servlet
resp.sendRedirect("test2?name=" + req.getParameter("name"));
}
}
ServletConfig, 是一个接口, 由Servlet容器创建该对象, 在Servlet初始化阶段, 用于为Servlet提供配置信息. 配置信息可以在web.xml中提供.
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_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>demo</servlet-name>
<servlet-class>com.bjsxt.servlet.DemoServlet</servlet-class>
<!--初始化参数-->
<init-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</init-param>
<init-param>
<param-name>gender</param-name>
<param-value>男</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>demo</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
</web-app>
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取ServletConfig对象
ServletConfig config = getServletConfig();
// 获取初始化参数
String name = config.getInitParameter("name");
String gender = config.getInitParameter("gender");
System.out.println("name = " + name);
System.out.println("gender = " + gender);
}
}
ServletContext, 是一个接口, 表示整个web应用. 一个应用程序有且仅有一个ServletContext对象. 通常来讲, ServletContext也被称之为Application. 使用ServletContext可以实现以下操作: 读取全局初始化参数, 可以加载web项目的静态资源, 可以获取资源的真实路径等操作.
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取ServletContext对象
ServletContext c1 = getServletContext();
// 先获取ServletConfig, 然后获取ServletContext
ServletContext c2 = getServletConfig().getServletContext();
// 可以通过请求对象获取ServletContext
ServletContext c3 = req.getServletContext();
System.out.println(c1 == c2);
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
}
全局配置参数是独立于Servlet的, 所有的Servlet都可以使用全局初始化参数.
<!--全局初始化参数-->
<context-param>
<param-name>name</param-name>
<param-value>张无忌</param-value>
</context-param>
// 读取全局初始化参数
String name = c2.getInitParameter("name");
System.out.println("name = " + name);
// 加载静态资源, 指的是web目录下的内容, getResourceAsStream
InputStream is = c1.getResourceAsStream("WEB-INF/web.xml");
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
// 获取目录的真实路径, 不存在则创建
String upload = c3.getRealPath("/upload");
System.out.println("upload = " + upload);
File file = new File(upload);
if(!file.exists()) {
file.mkdirs();
}
路径问题解决定位问题, 相对路径(从当前位置出发进行定位), 绝对路径(从指定位置出发进行定位), 例如:
前台页面中, /表示服务器根路径, 定位时建议使用绝对路径.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>AAAA</h1>
<hr>
<a href="">当前位置</a>
<a href="/">服务器根路径</a>
<hr>
<ul>
<li>相对路径
<ul>
<li><a href="../../../../b/bb/bbb/bbb.html">bbb.html</a></li>
</ul>
</li>
<li>绝对路径
<ul>
<li><a href="/b/bb/bbb/bbb.html">bbb.html</a></li>
</ul>
</li>
</ul>
</body>
</html>
后台Servlet路径问题应该区别对待, 建议使用绝对路径定位.
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.service");
// 跳转到bbb.html
// 相对路径, 基于web.xml中配置的url-pattern
req.getRequestDispatcher("../b/bb/bbb/bbb.html").forward(req, resp);
// 绝对路径, 通过/定位, /表示项目根路径
req.getRequestDispatcher("/b/bb/bbb/bbb.html").forward(req, resp);
}
}
public class Demo2Servlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Demo2Servlet.service");
// 重定向到bbb.html
// 相对路径
resp.sendRedirect("../b/bb/bbb/bbb.html");
// 绝对路径, /定位, /表示的时服务器根路径
resp.sendRedirect(req.getContextPath() + "/b/bb/bbb/bbb.html");
}
}
12.1
java.lang.NoClassDefFoundError: Could not initialize class
12.2 eclipse将项目部署到Tomcat下出现HTTP Status 404
解决方法
12.3 servlet映射–eclipse中自己手动创建的xml文件为什么不生效
解决方法
12.4 500之后404
解决方法