JavaWeb
Servlet
编写一个HelloServlet 继承于 HttpServlet
public class HelloServlet extends HttpServlet{
//根据上图了解,在HelloServlet中我们需要重写HttpServlet中的doGet等方法,因为最常用的是Get 和 Post请求
@Override
protected void doGet(HttpServlet req,HttpServlet resp)throws ServletException,IOException{
PointWrite out = resp.getWriter();
out.print("hello,servlet");
}
@Override
protected void doPost(HttpServlet req,HttpServlet resp)throws ServletException,IOException{
//post和get的请求逻辑一样,所以可以复用doGet方法
doGet(req,resp);
}
}
注册servlet,配置servelet映射
<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.study.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
Servlet原理
Mapping问题
一个Servlet可以对应多个mapping
可以自定义路径后缀
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello.do</url-pattern>
</servlet-mapping>
默认请求路径,这样写会无法进入index
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
错误页面映射,映射路径为/* ,但是如果请求路径为/hello.do依旧会进入HelloServlet,Servlet会优先进入设定好的路径
<servlet>
<servlet-name>error</servlet-error>
<servlet-class>com.study.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*<url-pattern>
</servlet-mapping>
ServletContext
Web容器在启动的时候,会为每一个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用。
- 共享数据
在helloservlet的context中写入一个数据,在testServlet中获取
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.setAttribute("username","学习"); }
}
public class TestServlet 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); }
}
- 获取初始化参数
<!-- 配置web应用初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
public class DemoServlet 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); }
}
- 请求转发
转发:A->B->C
重定向:A->B B->A A->C
// 转发的请求路径
context.getRequestDispatcher("/test").forward(req,resp);
- 读取资源文件
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
ServletContext context = this.getServletContext();
InputStream resource = context.getResourceAsStream("/WEB-INF/classes/db.properties"); Properties properties = new Properties();
properties.load(resource);
String username = properties.getProperty("username");
String password = properties.getProperty("password"); resp.getWriter().print(username+":"+password);
}
可能会出现资源导出问题,需在pom.xml中配置
<!-- 在build中配置resources,来防止导出失败问题 -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
HttpServletResponse
常见应用
- 向浏览器发出消息
getWriter()和getOutPutStream
两者的区别:
getWriter 用于发送字符数据
getOutPutStream 用于发送二进制数据
但是两者不能同时使用
原因是servlet会将完成了输出流的response对象给服务器,服务器对response进行解析,会检查流是否关闭,如果没有关闭就会将输出流关闭,当response发现有另一个流被创建,然后尝试进行输出就会发生异常,所以两个流只能使用一个。
- 下载文件
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取下载文件路径
String path = "D:\\JavaWeb\\servlet-02\\target\\classes\\a.1.png";
System.out.println(path);
//获取下载文件名
String filename = path.substring(path.lastIndexOf("\\")+1);
//设置响应头,让浏览器可以支持下载需要的东西
resp.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(filename,"UTF-8"));
//获取下载文件输入流
FileInputStream in = new FileInputStream(path);
//创建缓冲区
byte[] buffer = new byte[1024];
int len=0;
//获取输出流
ServletOutputStream out = resp.getOutputStream();
//将输出流写入buff缓冲区,使用outputstream将缓冲区的数据输出到客户端
while((len=(in.read(buffer)))!=-1){
out.write(buffer,0,len);
}
//关闭资源
out.close();
in.close();
}
- 重定向
请求A到B, B告诉A要去C 并且还给A ,A再去C
@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
/*
resp.setHeader("Location","/hello");
resp.setSstatus(302);
*/
resp.sendRedirect("/hello");
}
转发时,url地址栏不会发生变化
重定向,url地址栏会发生变化
HttpServletRequest
- 获取前端传递的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqCeNHgo-1640075245133)(en-resource://database/529:1)]
2.请求转发
req.getRequestDispatcher("/success.jsp").forward(req,resp);
Cookie和Session
会话
用户打开浏览器,点击链接,访问多个web资源,这个过程就叫做会话。
有状态会话:客户端访问服务端,下次再访问的时候服务端知道这个客户端曾经来过
学生如何证明自己是该学校的学生
- 发票 学校开的学费发票
- 学生名单 学校把学生的名字登记在名单上
同理,网站如何知道一个客户端是否来过
- 服务端给客户端一个信件,客户端下次访问的时候带上信件就行,Cookie
- 服务端将客户端登记,下次访问时服务端查看是否登记, Session
** 保存会话的两种技术**
cookie 客户端技术(响应,请求)
session 服务器技术,可以保存用户的会话信息,把用户的信息或数据放在Session中,常见场景:网站登录过后,一段时间内再进入该网站不需要重新登录
Cookie
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
// cookie是服务器给客户端的信件,所以从请求中获取cookie
Cookie[] cookies = req.getCookies();
// 判断cookie是否为空,为空就是第一次来本站
if(cookies!=null) {
resp.getWriter().print("上一次访问本站的时间");
for (Cookie cookie : cookies)
{// 获取time的cookie
if(cookie.getName().equals("time")){
// 得到上一次访问本站的时间,是时间戳
Long value = Long.parseLong(cookie.getValue());
// 时间戳转换为时间
Date date = new Date(value);
resp.getWriter().print(date.toLocaleString());
}
}
}else{
resp.getWriter().print("第一次访问本站");
}
// 设置一个新的时间cookie 时间戳
Cookie cookie = new Cookie("time", System.currentTimeMillis() + "");
// 设置cookie有效时间 单位是s ,不设置有效期,关闭浏览器自动失效,
// 删除cookie 把有效期设置为0 添加一个同名的cookie来替代它
cookie.setMaxAge(24*60*60);
// 服务端放入新的cookie
resp.addCookie(cookie);
}
中文cookie可能会需要编码和解码
new Cookie("name",URLEncoder.encode("张三","utf-8"));
URLDecoder.decode(cookie.getValue(),"utf-8");
Session(重点)
服务器会给每一个用户(浏览器)创建一个Session对象;
一个Session独占一个卢兰其,只要浏览器没有关闭,这个Session就存在
用户登录之后,整个网站它都可以访问, 比如B站登录之后,可以进入用户管理中心,不登录就无法进入
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
HttpSession session = req.getSession();
session.setAttribute("name","张三");
String id = session.getId();
if(session.isNew()){
resp.getWriter().write("Session创建成功"+id);
}else{
resp.getWriter().write("Session已经存在 ");
}
// session移除
session.removeAttribute("age");
// 手动注销session
session.invalidate();
}
通常会在web.xml中配置session失效时间,手动注销用于用户手动注销账户,失效时间是自动注销
<session-config>
<!-- 以分钟为单位-->
<session-timeout>1</session-timeout>
</session-config>
Cookie和Session的区别
- Cookie把用户的数据写给用户的浏览器,存放在客户端,可以存放多个
- Session是把用户的数据写到用户独占的Session中,存放在服务端,一个浏览器一个Session,一般用来保存重要信息,减少服务器的资源浪费
- Session对象由服务端创建,虽然是用req.getSession()获取,但是不写这句话依旧存在
JavaBean
实体类,pojo ,entity
- 属性必须私有
- 要有无参构造
- 有对应的get/set方法
用来与数据库做对象关系映射 ORM
过滤器 Filter
- 处理中文乱码
- 登陆验证
在web服务器与Servlet中间加了一层过滤层,过滤垃圾请求
//Filter 是 javax.servlet 包下的
public class CharacterEncoding implements Filter {
@Override
public void init(FilterConfig filterConfig) throwsServletException{
System.out.println("过滤器初始化......");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChainchain)throwsIOException,ServletException{
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
System.out.println("过滤器执行中.......");
// chain 链 让请求继续往下走,可能是下一个过滤器,也可能是servletchain.doFilter(request, response); }
@Override
public void destroy() {System.out.println("过滤器销毁......"); }
}
还需要在web.xml中注册,配置映射
<filter>
<filter-name>character</filter-name>
<filter-class>com.study.filter.CharacterEncoding</filter-class>
</filter>
<filter-mapping>
<filter-name>character</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
监听器 Listener
public class OnlineListener implements HttpSessionListener {
@Override// 一旦创建Session 就会触发一次这个事件
public void sessionCreated(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer online = (Integer) context.getAttribute("online");
if(online==null){
online = 1;
}else{
int i = online.intValue();
online=new Integer(i++);
}
context.setAttribute("online",online);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer online = (Integer) context.getAttribute("online");
if(online==null){
online = 0;
}else{
int i = online.intValue();
online=new Integer(i--);
}
context.setAttribute("online",online); }
}
注册监听器
<listener>
<listener-class>com.study.linstener.OnlineListener</listener-class>
</listener>