在Servlet中可以使用的内置对象主要有:request、response、application(应用程序)、session(会话)、out(PrintWriter)。
一、response对象
1.1 ServletResponse简介
定义辅助 servlet 将响应发送到客户端的对象。servlet 容器创建 ServletResponse 对象,并将它作为参数传递给 servlet 的 service 方法。 要发送 MIME 正文响应中的二进制数据,请使用 getOutputStream 返回的 ServletOutputStream。要发送字符数据,请使用 getWriter 返回的 PrintWriter 对象。
1.2 HttpServletResponse介绍
扩展 ServletResponse 接口以提供特定于 HTTP 的发送响应功能。例如,该接口拥有访问 HTTP 头和 cookie 的方法。 客户端向服务器发起的都是HTTP协议操作,所以我们大部分使用HttpServletResponse对象作为直接操作对象!
1.3 HttpServletResponse 常用API介绍
方法名称 | 作用 |
---|---|
setStatus(int code) | 设置响应状态码:200 成功 302 临时重定向 304 处理缓存 404 Not Found没有找到资源,500 服务器错误 |
setHeader(name,value) | 设置响应信息头 |
setCharacterEncoding(String); | 设置编码格式 |
setContentType(String) | 设置返回数据mimetype |
getWriter() | 获取字符输出流 |
getOutputStream() | 获取字节输出流 |
getServletContext() | 一个servlet可以使用getServletcontext()方法得到了web应用中的Servletcontext,从而使用Servletcontext接口的一些方法,比如getRealPath获取实际路径,可以用于获取web下的文件 |
1.4 案例一——预览和下载图片(两种方式)
预览和下载,只是差一个方法的问题,但是不能共存
//如果将图片放到了web文件夹下,则需要通过getServletContext()方法获取
@WebServlet(name = "DownServlet", value = "/downservlet")
public class DownServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用application获取web下的图片
//一个servlet可以使用getServletcontext()方法得到了web应用中的Servletcontext,从而使用Servletcontext接口的一些方法
ServletContext servletContext = this.getServletContext();
//通过servletContext使用接口中方法,getRealPath获取实际路径
String realPath = servletContext.getRealPath("img/蜜獾.jpg");
//设置响应头,content-disposition内容如何处理,如何配置,保存,进行下载处理,与显示是分开独立的,不能既显示又下载,这里要设置编码,否则无法正常显示图片
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("img/蜜獾.jpg", "utf-8"));
FileInputStream fis = new FileInputStream(realPath);
ServletOutputStream os = response.getOutputStream();
byte[] bytes = new byte[1024 * 8];
int len = -1;
while ((len = fis.read(bytes)) != -1) {
os.write(bytes, 0, len);
os.flush();
}
fis.close();
os.close();
System.out.println("执行完毕");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
//如果图片在src文件夹下,则使用类加载器获取
@WebServlet(name = "DownLoadServlet", value = "/downloadservlet")
public class DownLoadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InputStream is = DownLoadServlet.class.getClassLoader().getResourceAsStream("img/蜜獾.jpg");
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("img/蜜獾.jpg", "utf-8"));
ServletOutputStream os = response.getOutputStream();
byte[] buf = new byte[1024 * 8];
int len = -1;
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len);
os.flush();
}
is.close();
os.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
1.5 案例二——页面中添加验证码
项目中要导入jar包:validatecode.jar
创建并返回验证码的servlet
注:验证码就是一个图片
验证码servlet类
@WebServlet(name = "ValidatecodeServlet", value = "/vs")
public class ValidatecodeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建验证码
//宽度、高度、个数、干扰线个数
ValidateCode validateCode = new ValidateCode(120,30,4,25);
String code = validateCode.getCode();
System.out.println("验证码" + code);//可以获取验证码值在控制台打印,也可以不用打印
//验证码图片给到浏览器
validateCode.write(response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
注册类,使用验证码【重点】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<h2>用户注册</h2>
<form action="registservlet" method="post" enctype="application/x-www-form-urlencoded">
用户名<input type="text" name="username"/><br/>
密码<input type="password" name="password"/><br/>
确认密码<input type="password" name="repassword"/><br/>
邮箱<input type="email" name="email"/><br/>
验证码:<img id="codeing" src="/0831web1/vs" onclick="changeing()"/>
<!--必须有href,否则不能点击,里面为空,表示刷新本页面-->
<!--onclick中内容为方法,下面可知返回为false,再来一个return false将结果给a标签,要求不刷新本页面-->
<a href="" onclick="return changeing()">看不清</a><br/>
<input type="submit" value="提交"/><br/>
</form>
<script type="text/javascript">
function changeing() {
var codeing = document.getElementById("codeing");
//?及?号后面的代码不影响路径,不影响查找到vs,这里目的是给vs一个路径,让vs以为页面变化了,从而刷新验证码,但其实并未跳转其他页面
codeing.src="/0831web1/vs?n=" + Math.random();
return false; //不允许跳转页面,将值返回给a标签,保证不刷新本页面
}
</script>
</body>
</html>
二、request对象
2.1 ServletRequest介绍
定义将客户端请求信息提供给某个 servlet 的对象。servlet 容器创建ServletRequest 对象,并将该对象作为参数传递给该 servlet 的service方法
2.2 HttpServletRequest介绍
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,开发人员通过这个对象的方法,可以获得客户这些信息。
同响应相同,客户端请求协议都是基于HTTP所以我们选用HttpServletRequest来操作用户发送过来的请求的数据!
2.3 HttpServletRequest常用API
URL :Uniform Resource Location (统一资源定位符) 网址,是一个地址
URI :Uniform Resource Identifier (统一资源标识符) URI包含URL,是一个名字
方法的使用:
getRequestURL方法返回客户端发出请求时的完整URL。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
getMethod得到客户机请求方式
//获取请求头信息
getHead(name)方法
getHeaders(String name)方法
getHeaderNames方法
//获取请求正文参数
getParameter(name)方法
getParameterValues(String name)方法,返回字符串数组,用于多选框
getParameterNames方法
getParameterMap方法 //做框架用,非常实用
getInputStream方法 获取输入流
setAttribute方法,键值对存储
getAttribute方法,根据键获取值
removeAttribute方法, 根据键删除
@WebServlet(name = "RequestServlet",value = "/requestservlet")
public class RequestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取request对象信息
System.out.println("URL:" + request.getRequestURL());
System.out.println("URI:" + request.getRequestURI());
//查询的是在地址栏中get获取的?号后面的字符串内容
System.out.println("查询字符串getQueryString:" + request.getQueryString());
System.out.println("远端IP地址getRemoteAddr:" + request.getRemoteAddr());
System.out.println("远端主机getRemoteHost:" + request.getRemoteHost());
System.out.println("远端端口号getRemotePort:" + request.getRemotePort());
System.out.println("本地IP地址getLocalAddr:" + request.getLocalAddr());
System.out.println("本地端口号getLocalPort:" + request.getLocalPort());
System.out.println("------请求头-------");
String accept = request.getHeader("accept");
System.out.println(accept);
System.out.println("-----getHeaderName请求头属性和值------");
//是一个枚举选择器
Enumeration<String> headerNames = request.getHeaderNames();
//循环遍历
while (headerNames.hasMoreElements()) {
String headname = headerNames.nextElement();
//通过请求头名称获取值
System.out.println(headname + "==" + request.getHeader(headname));
}
System.out.println("attribute集合的使用");
//该集合必须先放入数据,然后才能获取数据
request.setAttribute("username", "Jack");
request.setAttribute("age", "20");
Object username = request.getAttribute("username");
Object age = request.getAttribute("age");
System.out.println(username + "...." + age);
request.removeAttribute("username");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
//打印结果:
URL:http://localhost:8080/0831web1/requestservlet
URI:/0831web1/requestservlet
查询字符串getQueryString:null
远端IP地址getRemoteAddr:0:0:0:0:0:0:0:1
远端主机getRemoteHost:0:0:0:0:0:0:0:1
远端端口号getRemotePort:62496
本地IP地址getLocalAddr:0:0:0:0:0:0:0:1
本地端口号getLocalPort:8080
------请求头-------
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
-----getHeaderName请求头属性和值------
host==localhost:8080
connection==keep-alive
upgrade-insecure-requests==1
user-agent==Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
sec-fetch-mode==navigate
accept==text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
sec-fetch-site==none
accept-encoding==gzip, deflate, br
accept-language==zh-CN,zh;q=0.9
cookie==Idea-b2e7a278=580841ca-1fcd-4ccf-ad1b-446395a835aa; username=??????
attribute集合的使用
Jack....20
三、案例——封装请求参数
将从前端页面获取的数据封装到实体类上,创建一个对应的实体类,实体类变量命名和变量类型都有相应的要求,要求变量名跟提交参数的key相同,变量跟参数类型相同!
User类
只列举属性,略去set和get方法,以及toStirng方法等
public class User {
private Integer id;
private String username;
private String password;
private String gender;
private String[] hobby;
public User() {
}
public User(Integer id, String username, String password, String gender, String[] hobby) {
this.id = id;
this.username = username;
this.password = password;
this.gender = gender;
this.hobby = hobby;
}
}
html文件,info信息的提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户信息</title>
</head>
<body>
<h2>用户信息</h2>
<form action="infoservlet" method="post" enctype="application/x-www-form-urlencoded">
学号<input type="text" name="id"><br/>
用户名<input type="text" name="username"/><br/>
密码<input type="password" name="password"/><br/>
性别<input type="radio" name="gender" value="man"/>男
<input type="radio" name="gender" value="woman"/>女<br/>
爱好<input type="checkbox" name="hobby" value="book"/>看书
<input type="checkbox" name="hobby" value="javaBook"/>看java书
<input type="checkbox" name="hobby" value="movie"/>看电影
<input type="checkbox" name="hobby" value="music"/>听音乐<br/>
<input type="submit" value="提交">
</form>
</body>
</html>
infoServlet获取前端信息的方式
一共有三种方式:getParameter、反射和内省来封装、BeanUtils
@WebServlet(name = "infoServlet", value = "/infoservlet")
public class infoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
/*一、使用getParameter获取,此方法是先获取再封装,很麻烦*/
Integer id = Integer.valueOf(request.getParameter("id"));
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
String[] hobby = request.getParameterValues("hobby");
User user = new User(id,username, password, gender, hobby);
System.out.println(user.toString());
/*二、反射和内省来封装,是BeanUtils的原理,这里注意数据类型的处理以及内省机制*/
User user = new User();
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
try {
PropertyDescriptor pd = new PropertyDescriptor(key, User.class);
if (pd != null) {
String[] value = entry.getValue();
Method writeMethod = pd.getWriteMethod();
//值会重复不唯一,所以entry.getValue()获取的是数组
//有的key对应的值是唯一的,比如username,所以只需要value[0]赋值即可
//有的key对应的值是很多的,比如hobby,需要将地址给hobby,自然不能用value[0]
//所以需要判断
if(pd.getPropertyType().isArray()) {
//同样,entry.getValue()获取的类型都是String,但是对应的hobby数组类型不一定是String,需要转型
writeMethod.invoke(user, (Object) value);
} else {
//需要判断是否为Integer类型,否则需要进行转换
if (pd.getPropertyType() == Integer.class) {
writeMethod.invoke(user, Integer.parseInt(value[0]));
} else {
writeMethod.invoke(user, value[0]);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(user.toString());
/*三、使用Apache BeanUtils进行快速映射*/
User user = new User();
try {
BeanUtils.populate(user, request.getParameterMap());
System.out.println(user.toString());
//其他方法
//复制
User user2 = new User();
BeanUtils.copyProperties(user2, user);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
第三种方式,必须导入jar包:beanutils对应jar包、logging日志、commons-collections-3.2.1.jar。