简介
sun公司开发动态web的一门技术,sun在这些api中提供一个接口叫做Servlet,如果你想开发一个Servlet程序,只需要完成2步:
(1)编写一个类,实现Servlet接口。
(2)把开发好的java类部署到web服务器中。
把实现了Servlet接口的java程序叫Servlet。
编写一个Servlet
(1)编写一个普通的类
(2)实现Servlet接口,这里我们直接继承 HttpServlet(HttpServlet如果之前没有用到此包,需要从maven仓库下载,本人从maven仓库下载完,安装好依赖,访问时报错了,大体意思为:我们编写的类不是Servlet,在下边有解决方案。)
(3)重写Servlet的 doGet 和 doPost 方法
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter write = resp.getWriter(); // 创建响应流
write.print("哈哈;");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(4)编写Servlet的映射
为什么需要映射:我们写是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给它一个浏览器访问的路径。
在webapp -> WEB-INF -> web.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<!--
客户端请求时,会请求 http://localhost:8080/servlet_03_01_war/hello
根据/hello 会找到name为hello的类,然后根据com.lxc.HelloServlet找到我们编写的
对应的java程序类。
-->
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lxc.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
(5)注意一个问题,输入路径访问时,有可能报类似如下的错误:
首先,先去检查下是类名、和配置的Servlet映射是否正确,如果都对的话,那百分之99的问题出在jar包依赖的问题上,tomcat10之后不是 javax.servlet 了,而是 jakarta.servlet,所以Web的依赖应该换成下面的这两个,换了之后就对了。
在pom.xml中把原来的依赖更换成如下代码,此时就能仿问了:
<!--jsp的依赖-->
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<!--jar包的依赖-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
Mapping
(1)一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
(2)一个Servlet可以指定多个映射路径
多个路径,都会被映射到名字为hello对应的类中
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
</web-app>
(3)一个Servlet可以指定通用映射路径
下边代表 /hello/ 后边不管写什么东西, 都会被映射到名字为hello对应的类中
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
(4)指定一些后缀
下边写法,只要后缀时.xxx的被映射到名字为hello对应的类中
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.xxx</url-pattern>
</servlet-mapping>
404页面
(1)默认的404页面,是由Servlet提供的,如果不想使用它的,我们可以定义404页面
// 创建Error类
public class Error extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter write = resp.getWriter();
write.print("<h1>404</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
Servlet映射
error我们使用的 /* 通配符,他的优先级是最低的,固有的路径的优先级最大,所以当我们当问/hello时,走的是名字为hello对应的类中,如果没在这里映射,那么他会走我们编写的error页面!
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.lxc.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
<!--Error类的映射-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.lxc.Error</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Servlet常用API
(1)getServletContext - 实例方法
web容器在启动的时候,都会为每个web容器创建一个ServletContext上下文对象且是唯一的,它代表了当前的web应用,而这个上下文对象我们可以使用它来做数据共享。
getServletContext 返回的是一个上下文对象,Servlet之间通信可以使用该方法,来传递数据。
web.xml中的配置就不展示了
// User.java
public class User extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8"); // 设置编码
resp.setContentType("text/plain");
ServletContext ctx = this.getServletContext(); // 获取上下文
String name = "吕星辰";
ctx.setAttribute("name", name); // 保存数据
resp.getWriter().print("数据保存成功!");
}
}
// getUserInfo.java
public class GetUserInfo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.setCharacterEncoding("utf-8");
ServletContext ctx = this.getServletContext();
// getAttribute返回的结果Object对象,所以需要强转为String
String res = (String) ctx.getAttribute("name");
resp.getWriter().print("返回的结果为:"+res);
}
}
输出结果:
(2)ctx.getInitParameter 获取初始化参数 - 上下文对象中的方法
<!--web.xml-->
<!--···-->
<context-param>
<param-name>name</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
<!--···-->
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext ctx = this.getServletContext(); // 获取上下文
// 获取web.xml中初始化的参数 jdbc:mysql://localhost:3306/mybatis
String name = ctx.getInitParameter("name");
}
(3)ctx.getRequestDispatcher(String url) 请求转发 - 上下文对象中的方法
注意,此方法转发之后路径不会改变,与重定向的区别是:重定向之后页面URL会变化。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext ctx = this.getServletContext(); // 获取上下文
RequestDispatcher dir = ctx.getRequestDispatcher("/redirect"); // 转发到 "/redirect"对应的页面
dir.forward(req, resp);
}
(4)ctx.getResourceAsStream( ) 读取资源文件
在resources中创建了 dn.properties 的资源文件,我们来定义用户名和密码:
在ReadFile.java中读取它:
public class ReadFile extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext ctx = this.getServletContext();
// 获取资源的流
InputStream streams = ctx.getResourceAsStream("/WEB-INF/classes/db.properties");
// 关于Properties 会有专门的一篇文章记录
Properties prop = new Properties();
prop.load(streams); // 加载流
String username = prop.getProperty("username"); // 读取属性
String password = prop.getProperty("password");
resp.getWriter().print("username:"+username+",password:"+password);
}
}
上边getResourceAsStream() 中的参数是资源的路径,在项目打包编译之后,会生成target文件,我们只需要查看资源打包编译之后,在哪里即可,这样项目部署在服务器上的时候,就不需要更改资源路径了。
注意一个问题:
如果资源文件没有放到 resources文件下,放到了别的地方,此时,打包编译之后,资源文件会被忽略,不会被打包进去,解决这个问题,我在Maven下载安装配置一文中已经记录。
(5)resp.sendRedirect()重定向
public class Response extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/redirect"); // 重定向到 redirect路径
}
}
原理
public class Response extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setHeader("localtion", "/redirect"); // 参数二为重定向的路径
// resp.setStatus(302);
resp.sendRedirect("/redirect"); // 重定向到 redirect路径
}
}
重定向与转发的区别
不同点:转发url不会发生变化;重定向url会发生变化。
相同点:页面跳转