Servlet简介
Servlet是sun公司开发动态web的一门技术
Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需完成下面两步:
编写一个类,实现Servlet接口
把开发好的Java类部署到Web服务器中
把实现了Servlet接口的Java程序叫做Servlet
二、构建一个Servlet项目
Servlet接口Sun公司有两个默认的实现类:HttpServlet、GenericServlet
分析源码:
编写程序
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello Servlet");
// resp.setContentType("");
resp.setCharacterEncoding("utf-8");
PrintWriter writer = resp.getWriter();
writer.println("Hello Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
编写Servlet映射
为什么需要映射:我们写的是Java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的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"
metadata-complete="true">
<!-- 注册Servlet-->
<servlet>
<!-- 匿名-->
<servlet-name>hello</servlet-name>
<!-- 完整类名-->
<servlet-class>com.sv.HelloServlet</servlet-class>
</servlet>
<!-- servlet请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!-- 访问该Servlet的虚拟路径,该路径以/开头,代表应用程序的根目录-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.sv.ErrorServlet</servlet-class>
</servlet>
<!-- servlet请求路径-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Servlet原理
Servlet是由Web服务器(tomcat)调用,web服务器(tomcat)在收到浏览器请求之后,会:
Mapping问题
#注意:*前面不能加项目映射的路径
1、一个Servlet可以指定一个映射路径
<url-pattern>/hello</url-pattern>
2、一个Servlet可以指定多个映射路径
<url-pattern>/hello</url-pattern>
<url-pattern>/hello1</url-pattern>
<url-pattern>/hello2</url-pattern>
3、一个Servlet可以指定通用映射路径
<url-pattern>/*</url-pattern>
4、指定一些后缀或者前缀等等
5、优先级问题
指定了固有的映射路径优先级最高,如果找不到,就会走默认的处理请求
二、ServletContext(后期不会使用,但为后期开发做铺垫,属于后期的影子)
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用
1、共享数据(后期用session去做)
我在这个Servlet中保存的数据,可以在另一个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"
metadata-complete="true">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.sv.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>gets</servlet-name>
<servlet-class>com.sv.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gets</servlet-name>
<url-pattern>/gets</url-pattern>
</servlet-mapping>
</web-app>
发送端Servlet:
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);
System.out.println("hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
接收端Servlet:
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("名字"+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
#注意:text/html的意思是将文件的content-type设置为text/html的形式,浏览器在获取到这种文件时会自动调用html的解析器对文件进行相应的处理。
2、获取初始化参数
配置xml
<!-- 设置一些web应用的初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybaits</param-value>
</context-param>
<servlet>
<servlet-name>db</servlet-name>
<servlet-class>com.sv.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>db</servlet-name>
<url-pattern>/db</url-pattern>
</servlet-mapping>
编写程序:
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String s = context.getInitParameter("url");
resp.getWriter().print(s);
}
3、请求转发(后期用request去做)
请求转发寻求路径A-C模型:
重定向寻求路径A-C模型:
编写xml:
<servlet>
<servlet-name>co</servlet-name>
<servlet-class>com.sv.Servletemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>co</servlet-name>
<url-pattern>/co</url-pattern>
</servlet-mapping>
编写程序:
public class Servletemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/db"); //转发的请求路径
// requestDispatcher.forward(req,resp); //调用forward实现请求转发
context.getRequestDispatcher("/db").forward(req,resp);
}
4、读取资源文件(后期会用反射和类加载器)
Properties
在Java目录下新建properties
在resources目录下新建properties
发现:都被打包到了同一路径下:classes,我们俗称这个路径为classpath(类路径)
思路:需要一个文件流
xml配置:
<servlet>
<servlet-name>po</servlet-name>
<servlet-class>com.sv.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>po</servlet-name>
<url-pattern>/po</url-pattern>
</servlet-mapping>
编写程序:
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(is);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().print(username+";"+password);
}
六、HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse
如果要获取客户端请求过来的参数:找HttpServletRequest
如果要给客户端相应一些信息:找HttpServletResponse
1、简单分类
负责向浏览器发送数据的方法(追溯源码ServletResponse )
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
响应状态码
2、常见应用
1、像浏览器输出消息
2、下载文件
1、要获取下载文件的路径
2、下载的文件名是啥?
3、设置想办法让浏览器能偶支持下载我们需要的东西
4、获取下载文件的输入流
5、创建缓冲区
6、获取OutputStream对象
7、将FileOutputStream流写入到buffer缓冲区
8、使用OutputStream将缓冲区中的数据输出到客户端
测试:
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1、要获取下载文件的路径
String realPath = "E:\\Code\\JavaCode\\java-web-servlet\\servlet02\\target\\classes\\src=http___i0.hdslb.com_bfs_article_d75e90f804db9b156bc77fe90bd5e38d6bc43141.jpg&refer=http___i0.hdslb.png";
System.out.println("下载文件的路径"+realPath);
// 2、下载的文件名是啥?
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
// 3、设置想办法让浏览器能偶支持下载我们需要的东西
resp.setHeader("Content-Disposition","attachment;filename"+filename);
// 4、获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
// 5、创建缓冲区
int len=0;
byte[] buffer = new byte[1024];
// 6、获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
// 7、将FileOutputStream流写入到buffer缓冲区 8、使用OutputStream将缓冲区中的数据输出到客户端
while ((len=in.read(buffer))>0){
out.write(buffer,0,len);
}
in.close();
out.close();
}
2、验证码
3、重定向
B一个web资源收到客户端A请求后,B它会通知A客户端去访问另一个web资源C,这个过程叫重定向
常见场景:
* 用户登录
resp.sendRedirect("转发路径");
测试:
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("/servlet02_war/down");
}
七、HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest方法,获得客户端的所有信息
1、获取前端传递参数
req.getParameter()
req.getParameterValues()
2.测试
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
System.out.println("================");
System.out.println(req.getContextPath());
//通过请求转发
//这里的/代表当前的web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
<h1>登录</h1>
<div style="text-align: center">
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbys" value="女孩">女孩
<input type="checkbox" name="hobbys" value="代码">代码
<input type="checkbox" name="hobbys" value="唱歌">唱歌
<input type="checkbox" name="hobbys" value="电影">电影
<br>
<input type="submit">
</form>
</div>
面试题:请你聊聊重定向和转发的区别
相同点
页面都会实现跳转
不同点
请求转发的时候,url不会产生变化 307
重定向的时候,url地址栏发生变化 302