servlet
1. servlet简介
-
开发动态web
-
servlet接口:
-
编写一个类,实现servlet接口
-
把开发好的Java类部署到web服务器中
-
2. HelloServlet
Servlet有两个默认的实现类:HttpServlet,
-
构建一个普通的maven项目,删掉src目录
-
添加servlet依赖:(jsp也要用到,一同添加)(ps:类似于python导包
<!-- 添加依赖 -->
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies> -
关于maven父子项目:
父项目的pom.xml中有modules:
<modules>
<module>servlet-01</module>
</modules>子项目的pom.xml中有parent:
<parent>
<artifactId>javaweb-02-servlet</artifactId>
<groupId>com.mystudy</groupId>
<version>1.0-SNAPSHOT</version>
</parent>父项目中的jar包子项目可以直接用
-
maven环境优化
-
更新web.xml 4.0版本
<?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"
metadata-complete="true">
<display-name>Archetype Created Web Application</display-name>
</web-app> -
将maven的结构搭建完整(添加resources、java文件夹)
-
-
编写一个servlet程序
-
编写一个普通类
-
实现Servlet接口,这里直接继承HttpServlet类
public class HelloServlet extends HttpServlet {
// get和post是请求实现的不同方式,可以互相调用,业务逻辑都一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter(); //响应流
writer.print("Hello,Servlet!!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
-
-
编写servlet的映射
为什么需要映射:我们写的是Java程序,但是通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的servlet,还需要给它一个浏览器能访问的路径。
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.mystudy.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>注意:<url-pattern>/hello</url-pattern>hello前面的斜杠一定要加
-
配置Tomcat
注意:配置项目发布的路径即可
-
启动测试
3. servlet原理
-
浏览器发送Http请求到服务器端;
-
Web容器(例如Tomcat)接受到http请求,若是第一次访问Tomcat,则会生成一个servlet对应的target文件,并把我们写的实现类编译为.class文件;
-
web容器产生两个对象,Request和Response;
-
Request和Response对象作为参数调用Servlet中的Service方法;
-
Request会从service (请求)拿到请求并且把请求之后的响应交给Response;
-
最后从Response对象返回到web容器中;
-
Web容器把返回内容响应给客户端。
4. servlet-mapping
参考:Servlet原理和Mapping映射关系 - 知乎 (zhihu.com)
4.1 优先级问题
指定了固有的映射路径优先级最高,如果找不到就会走默认的映射。
例子:404页面
web.xml
<!--404-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.mystudy.servlet.ErrorServlet</servlet-class>
</servlet>
<!--Servlet请求路径-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ErrorServlet.java
public class ErrorServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.print("<h1>404</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5. ServletContext
5.1 数据共享
类似于session功能,一个servlet中的值可以传递给另一个servlet
因此必须按顺序运行
例子
HelloServlet.java
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = "惺惺相惜"; // 数据
context.setAttribute("username",username); // 将数据保存在ServletContext中(键值对的形式)
System.out.println("hello!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
GetServlet.java
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
ServletContext context = this.getServletContext();
String username = (String)context.getAttribute("username");
resp.getWriter().print("名字为:"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml
<?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"
metadata-complete="true">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.mystudy.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.mystudy.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
</web-app>
注意
-
必须先运行/hello再运行/getc。获取到username的值,才能进行传递,否则getc/得到的值为null;
-
这里创建了一个新的模块,注意要重新配置tomcat的war文件。(具体原因?)
5.2 获取初始化参数
先在web.xml设置初始化参数(例如mysql的url)
<!-- 配置初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
写servlet应用ServletDemo03.java
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().print(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
运行结果:
5.3 请求转发
getRequestDispatcher("/路径")
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// 分开的写法
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/getp"); //定义转发的目的地
// requestDispatcher.forward(req,resp); //转发。(req,resp参数为默认)
// 合并的写法
context.getRequestDispatcher("/getp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5.4 读取资源文件
properties类
-
在java目录下新建properties
-
在resources目录先新建properties
发现:都被打包到了同一路径下(classes),我们称之为classpath。
思路:需要一个文件流 getResourceAsStream()
重点:properties所在的路径
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/mystudy/servlet/aa.properties");
Properties prop = new Properties();
prop.load(is);
String user = prop.getProperty("username");
String pwd = prop.getProperty("password");
resp.getWriter().print(user+": "+pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}