Servlet和HTTP
Servlet和HTTP
Servlet的体系结构
Servlet---->GenericServlet---->HttpServlet
- GenericServlet:将Servlet接口中的其他方法默认空实现,只将service方法实现,通过extends个可以继承该类并复写service方法
- HttpServlet:继承HttpServlet方法,复写doGet和doPost方法,实质是对http协议的封装,简化操作;推荐使用这种方法
Servlet的相关配置
urlPattern:Servlet的访问路径
- 一个Servlet可以定义多个访问路径
- 路径的定义规则:
- /path
- /path1/path2
- *.path
HTTP
-
概念:Hyper Text Transfer Protocol 超文本传输协议
-
特点
- 基于TCP/IP的高级协议
- 基于请求--响应模型,请求和响应一一对应
- 无状态协议:每次请求之间相互独立
-
请求消息数据格式 request
-
请求行
请求方式(常用两种):
- GET:请求参数在url后,url长度有限制,不安全
- POST:请求参数在请求体中,url长度没有限制
请求方式 url 请求协议/版本
get /page.html HTTP/1.1
-
请求头(键值对)
Host:请求地址
User-Agent:浏览器版本
Accept:接受文件类型
Referer:请求来源;用于防盗链和数据统计
Connection:连接能否复用
请求头名称:请求头值
-
请求空行
分割行
-
请求体
正文;传递请求参数
-
-
request对象
-
request和response对象的原理
- 流程:服务器根据请求创建对象,tomcat将request和response对象传递到service方法;在service方法中处理业务逻辑并返回;服务器从response中拿到响应消息返回给浏览器
- request和response对象由服务器创建
- request对象用来获取请求消息
- response对象用来设置响应消息
-
request继承体系
ServletRequest-->HttpServletRequest-->org.apache.catalina.connector.RequestFacade
-
request功能
-
获取请求消息数据
-
请求行
GET /myproject/demo?name=zhangsan HTTP/1.1
方法:
1. 获取请求方式:String getMethod() 2. **获取虚拟目录:String getContextPath()** 3. 获取Servlet路径:String getServletPath() 4. 获取请求参数:String getQueryString() 5. **获取请求URI:String getRequestURI();String getRequestURL()** 6. 获取协议和版本:String getProtocol() 7. **获取客户机IP地址:String getRemoteAddr()** -
请求头
获取请求头:String getHeader(String name)
迭代器获取所有请求头:Enumeration
getHeaderNames() 获取user-agent、referer等
-
请求体
在POST请求中获取请求体
-
获取流对象
BufferReader getReader():只能操作字符
ServletInputStream getInputStream:获取字节输入流,可以操作所有类型的数据
BufferedReader bufferedReader = req.getReader(); String line = null; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } -
在流对象中拿数据
-
-
-
其他功能
-
获取请求参数值的通用方法:
中文可能出现乱码,Get方式不会乱码,Post可能会乱码,需要添加request.setCharacterEncoding("utf-8")
- 获取请求参数值:String getParameter(String name),可直接获取指定的参数
- 获取所有请求参数值:String[] getParameterValues(String name)
- 获取所有请求参数名称:Enumeration
getParameterNames() - 获取所有参数数据的Map集合:Map<String, String[]> getParameterMap();
-
请求转发
-
步骤:
- 通过request对象获取转发器对象:RequestDispatcher getRequesetDispatcher(String path)
- 通过RequestDispatcher对象的forward方法进行转发:forward(ServletRequest req, ServletResponse reps)
-
特点:
- 浏览器地址不变
- 只能转发到当前服务器内部的资源
- 转发只有一次请求
-
数据共享:
-
域对象:限制作用范围的对象
request域:只在一次请求的范围
- setAttribute(String name, Object obj) 存储数据
- Object getAttribute(String name) 通过key获取value
- removeAttribute(String name) 通过key删除key-value
-
-
获取ServletContext
ServletContext getServletContext()
-
-
-
-
-
综合案例
-
简单登录页面的工作流程:
-
创建数据库,设置好用户信息表
create table user ( id int auto_increment primary key, username varchar(32) not null, password varchar(32) not null, constraint username unique (username) ); -
在src下创建entity包,用于存放持久类,可通过工具一键生成getter和setter
package com.lijie.presistence; public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } -
创建dao包,用于存放数据操作类
package com.lijie.dao; import com.lijie.presistence.User; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import com.lijie.utils.jdbcUtil; public class userDao { private JdbcTemplate template=new JdbcTemplate(jdbcUtil.getDataSource()); /** * 登录方法 * @param user 只有用户名和密码 * @return 返回所有信息 */ public User login(User user){ try { String sql="select * from user where username=? and password=?"; return template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),user.getUsername(),user.getPassword()); }catch (DataAccessException e){ e.printStackTrace(); return null; } } } -
处理好数据库连接,可通过多种方法操作,例如JDBC、hibernate、mybatis等
-
编写servlet
- 首先需要创建一个登录界面的html文件,插入form元素,设置action和method
- action连接到执行用户信息匹配的servlet,按照form表单中提交的信息去数据库中查找,如果返回为空那么就说明信息不匹配,此时转发到"登录失败"的servlet;如果在数据库中却有此条数据,则连同此条数据一起转发到"登录成功"的servlet
-
-
JavaBean
-
什么是JavaBean?
标准的Java Class就是JavaBean:
- public修饰
- 无参构造方法
- 成员变量private修饰
- 提供public get和set方法
-
JavaBean功能:封装数据
-
概念
- 成员变量
- 属性:setter和getter方法获取到的值
-
populate()方法
BeanUtils.setProperty(entityObject, key, value)
BeanUtils.populate(entityObject, MapObject)
-
-
-
响应消息
-
数据格式:
-
响应行
-
组成:协议/版本 状态码 描述
-
状态码:
1XX:客户端问询服务器是否还有数据要传送
2XX:成功
3XX:重定向
4XX:客户端错误
5XX:服务器端错误
-
-
响应头
格式:头名称:值
Content-Type: text/html;charset=UTF-8
Content-Length:length
Content-disposition: in-line 以什么格式打开响应体,默认在当前页面中打开,多用于文件下载,以attachment格式打开
-
响应空行
-
响应体
响应字符串
-
-
功能:
- 设置响应行:setStatus(int status)
- 设置响应头:setHeader(String name, String value)
- 设置响应体:
- 获取输出流
- 字符流:PrintWriter gerWriter()
- 字节流:ServletOutputStream getOutputStream()
- 使用输出流
- 获取输出流
-
案例:
-
重定向:response.sendRedirect(String path)
- 地址栏发生变化
- 可以访问其他站点
- 两次请求,不能用response来共享数据
路径:
-
绝对路径:/myproject/servlet 前面的http://locahost:port先省略
-
相对路径:./index.html 设置了一个参考位置,以.开头
规则:确定访问的current page和target page的相对位置关系
最好通过动态获取虚拟目录,来判断访问路径 request.getContextPath()
-
输出字符数据到浏览器:
-
在获取流对象之前设置流的默认编码,设置为对应的字符集编码:response.setCharacterEncoding("UTF-8")
-
告诉浏览器响应消息所设置的编码:response.setContentType("text/html;charset=utf-8")
-
PrintWriter printWriter=resp.getWriter(); printWriter.write("<h1>Hello World!你好</h1>");
-
-
输出字节数据到浏览器:
- response.setContentType("text/html;charset=utf-8")
- ServletOutputStream servletOutputStream = response.getOutputStream();
- srevletOutputStram.write("HelloWorld".getBytes("utf-8"))
-
验证码案例:
-
-
ServletContext对象
- 概念:代表整个web应用,可以和程序的容器(服务器)通信
- 如何获取:request.getServletContext(); this.getServletContext()
- 功能
-
获取MIME类型:String getMimeType(String file)
-
域对象:共享数据
- setAttribute(String name, Object value)
- getAttribute(String name)
- remobeAttribute(String name)
作用范围,所有用户请求的数据
-
获取文件的服务器路径
-
-
案例:文件下载
-
页面显示超链接,点击提示下载框,完成文件下载
-
content-disposition:attachment;filename=FILENAME
-
步骤
- 新建imgDownload页面,插入a标签,href通过servlet传递下载文件的filename
- 新建servlet,通过request.getParameter得到文件的filename
- 通过servletContext.getRealPath()得到文件的真实路径
- 新建输入流FileInputStream参数为3得到的realpath
- 得到servletContext的mimeType
- 设置responseHeader的content-type
- 设置responseHeader的content-disposition为attachment
- 新建servletOutputSteam通过write方法写文件,可以采用buffer
- 完成后需要关闭文件输入流,fileinputStream.close
-
String filename=req.getParameter("filename"); ServletContext servletContext = this.getServletContext(); String realPath = servletContext.getRealPath("/img/" + filename); FileInputStream fileInputStream = new FileInputStream(realPath); String mimeType = servletContext.getMimeType(filename); resp.setHeader("content-type",mimeType); resp.setHeader("content-disposition","attachment;filename="+filename); ServletOutputStream outputStream = resp.getOutputStream(); byte[] buff=new byte[1024*8]; int len=0; while ((len=fileInputStream.read(buff))!=-1){ outputStream.write(buff,0,len); } fileInputStream.close(); -
中文文件名如何处理?
对于不同的user-agent分别处理,对于文件名采用不同的处理方式
-
-

浙公网安备 33010602011771号