Request
内容
- 请求头
- 请求参数 重点
- 域对象功能 重点
- 请求转发 重点
- 其他方法, 获取客户端信息, url相关的信息…
request作为域对象的功能
只在同一次请求内有效
获取请求头的方法
request与请求头相关的方法有:
- String getHeader(String name):获取指定名称的请求头;
- Enumeration getHeaderNames():获取所有请求头名称;
- int getIntHeader(String name):获取值为int类型的请求头。
其他方法
- int getContentLength():获取请求体的字节数,GET请求没有请求体,没有请求体返回-1;
- String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded,表示请求体内容使用了URL编码;
- String getMethod():返回请求方法,例如:GET
- Locale getLocale():返回当前客户端浏览器的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
- String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null,表示使用ISO-8859-1编码;
void setCharacterEncoding(String code)
:设置请求编码,只对请求体有效!注意,对于GET而言,没有请求体!!!所以此方法只能对POST请求中的参数有效! 重点String getContextPath()
:返回上下文路径,例如:/helloString getQueryString()
:返回请求URL中的参数,例如:name=zhangSan- String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
- StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
- String getServletPath():返回Servlet路径,例如:/oneServlet
- String getRemoteAddr():返回当前客户端的IP地址;
- String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
- String getScheme():返回请求协议,例如:http;
- String getServerName():返回主机名,例如:localhost
- int getServerPort():返回服务器端口号,例如:8080
请求转发
动态资源(Servlet) 跳转到其他资源(Servlet, html, jsp…)
转发写法
-
RequestDispatcher getRequestDispatcher(String path) 得到转发器对象
-
调用RequestDispatcher对象的forward(request,response)
RequestDispatcher.forward(request,response);
1与2合并:
request.getRequestDispatcher(String path).forward(request,response);
转发特点:
- 只发起一次请求
- 客户端的url不会变
- 服务器端的转发, 只能转发到服务器内部资源
request域 一般就是在请求转发中使用
获取请求参数
方法1:String getParamter(String name) 根据name获取一个请求参数名对应的一个值
第一种情况: 前端传递请求参数名, 并且传递值
结果: 传递值
第二种情况: 前端传递请求参数名,没有传递值 username=&email=111
结果: “”
扫描二维码关注公众号,回复: 15830719 查看本文章第三种情况: 前端没有传递请求参数名
结果: null
方法2:String[] getParameterValues(String name) 一个请求参数名对应多个值 例如获取复选框的取值
//一个请求参数名对应多个值
String[] love = request.getParameterValues("hobbyArr");//获取爱好(复选框)
//数组转换为集合
List<String> hobbyList = Arrays.asList(hobbyArr);
System.out.println("love:"+loveList);
//数组转换集合 Arrays.asList(arr)
//asList()这个方法返回的ArrayList不是集合体系中的ArrayList,是一个内部类ArrayList ,是只读的
hobbyList.add("唱歌");//出错!!!!!!
Arrays.asList()这个方法返回的ArrayList不是集合体系中的ArrayList,是一个内部类ArrayList ,是只读的
方法3:Map<String,String[]> getParameterMap() 获取所有的请求参数, 得到一个map集合 一般结合第三方jar, 把map转换为java对象
Map<String, String[]> parameterMap = request.getParameterMap();
遍历Map集合
1.先得到key集合 然后遍历key, 得到value 不推荐 2.得到EntrySet Entry(key/value键值对) 推荐
Map<String, String[]> parameterMap = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
System.out.println(entry.getKey() +"-->"+Arrays.asList(entry.getValue()));
}
浏览器缓存问题:
修改页面, 访问的时候,页面没有改, 可能是浏览器缓存问题
chrome: ctrl + F5 底层刷新
Response
内容
- 设置响应头
- 发送状态码
- 设置响应正文: 得到响应输出流,输出 重要
- 重定向 重要
设置响应头
- void setIntHeader(String name, int value) 设置响应头, 响应头的值int类型
- void addIntHeader(String name, int value)
- void addHeader(String name,String value) 设置响应头, 响应头的值String
- void setHeader(String name,String value)
- void setContentType(String )设置content-type的响应头
重要的响应头:
content-type: “text/html;charset=UTF-8”:
告诉浏览器, 服务器响应的内容类型 ,浏览器根据内容类型进行解析
charset: 只对对文本文件有效
取值类型
text/html: 响应html文本
图片: 二进制文件
- image/gif:gif图片格式
- image/jped:jpg图片格式
- image/png:png图片格式
css:
text/css
js:
text/javascript
json:
application/json
setHearder()
发送状态码 了解
- response.setStatus(200):设置状态码;
- response.sendError(404, “您要查找的资源不存在”):当发送错误状态码时,Tomcat会跳转到固定的错误页面去,但可以显示错误信息。
200: 成功
304: 转发
404: 资源不存在
405: 不支持请求方式
400: 失败请求
500: 服务器内部错误, 后台出现异常
响应正文
通过响应输出流
字符响应输出流: response.getWriter() 输出文本、json数据
字节响应输出流: response.getOutputStream() 万能流, 文本,文件
注意:
这个两个流不能共存, 同时使用, 会抛异常java.lang.IllegalStateException
案例: 服务器响应图片
response.setContentType("image/gif");
//使用字节响应输出流 网络IO
ServletOutputStream outputStream = response.getOutputStream();
//服务器响应一张图片 图片位于服务器硬盘
//1.使用本地输入IO流 读取服务器硬盘图片 到服务器内存
FileInputStream fis = new FileInputStream("D:\\图片\\nbagif.gif");
int content = -1; //变量, 内存
while((content = fis.read()) != -1){
//2.再使用网络输出IO流, 把服务器内存的资源写到客户端
outputStream.write(content);
}
重定向
response.sendRedirect(重定向的路径)
特点;
- 两次请求, request域无效
- 客户端地址栏发生变化
- 跳转发生在客户端
- 跳转资源:可以是服务器内部资源(无法跳转到WEB-INF目录的资源), 也可以是服务器外部资源
重定向与转发资源路径问题:
访问的项目名: /web
重定向到demo1.html
重定向的url写绝对路径: 直接写/ 表示忽略项目名
如果没有设置访问的项目名: 必须加 /项目名/资源路径
项目名 通过request.getContextPath()获取到
重定向的url: 统一的写: req.getContextPath()+"/资源路径"
resp.sendRedirect(req.getContextPath()+"/demo1.html");
//转发
// 转发的url, 有项目名,没有项目名, 都不需要加/项目名
// 统一写法: /资源路径req.getRequestDispatcher("/demo1.html").forward(req,resp);
重定向的路径
//req.getContextPath()+"/资源路径"
resp.sendRedirect(req.getContextPath()+"/demo1.html");
乱码处理
产生乱码的原因:项目的编码统一为UTF-8,而tomcat的编码(post)为ISO-8859-1
get请求, 通过url
处理方式:
-
Tomcat 从8开始, 处理Get请求编码, 默认使用的编码: UTF-8
-
Tomcat7或者之前的, 没有处理Get请求编码 编码还是ISO-8859-1
- 在server.xml 指定get请求编码: UTF-8 (tomcat 7之前可以设置)
<Connector URIEncoding= "UTF-8" connectionTimeout= "20000" port= "8888" protocol= "HTTP/1.1" redirectPort= "8443" />
- 对所有的web服务器都有效, 通过代码处理
//1.打散 byte[] bytes = name.getBytes("UTF-8"); //2.组装成字符串 name = new String(bytes,"UTF-8");
get请求时: byte[] bytes = name.getBytes(“UTF-8”);的取值要看tomcat的版本 tomcat7之前为ISO-8859-1
post请求, 通过请求体
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
乱码处理总结:
- get请求编码: tomcat8以上已经处理,不需要管
- post请求编码, 调用request.setCharacterEncoding(“UTF-8”);
- 响应编码设置: 响应编码(不区分get或post请求) response.setContentType(“text/html;charset=UTF-8”);
- 2,3代码在获取参数之前, 响应数据之前, 作为servlet前两行代码
案例 某资源一个IP地址一小时只能访问一次
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
ServletContext application = this.getServletContext();
Integer count = (Integer)application.getAttribute("count");
HashMap<String,Long> map = (HashMap) application.getAttribute("map");
if(map == null){
// application.setAttribute("map",new HashMap<String,Long>()); 错误
map = new HashMap<String,Long>();
}
if(count == null){
count = 0;
}
String ip = request.getRemoteAddr();
long visitTime = System.currentTimeMillis();
if(!map.containsKey(ip)){
map.put(ip,visitTime);
count++;
}else {
if(System.currentTimeMillis()-map.get(ip)<3600000){
response.getWriter().println("刚刚来过啦,过会再来吧~");
}else {
map.put(ip,System.currentTimeMillis());
count++;
}
}
response.getWriter().print("<h1>本页面一共被访问" + count + "次!</h1>");
application.setAttribute("count", count);
application.setAttribute("map",map);
}
JSP
JSP
本质是一个Servlet的Java类
jsp是动态的资源包含Java脚本、html,浏览器无法直接访问
浏览器请求jsp, 需要web服务器执行jsp的代码, 执行之后的结果转换静态的html,响应给浏览器
JSP脚本
- <%…%>:java方法内能写的代码,都可以写在它内部
- <%=…%>:表达式, 表达式的结果在页面展示
- <%!..%>:Java定义类成员;定义属性,定义方法
jsp本质相当于是一个Servlet的Java类
JSP指令
jsp九大内置对象-- 面试题
内置对象: 不需要创建,可以直接使用
四大域对象: pageContext, request,session,application
响应对象: response
响应流对象: out
配置对象: config
表示this: page
异常对象: exception
会话跟踪技术 Cookie Session
http是无状态的,服务器无法区分浏览器的请求是否来自同一个浏览器
Cookie特征:
创建于服务器, 保存在客户端浏览器, 以后每次请求, 把该服务器存在客户端的浏览器的cookie通过请求头带回到服务器
使用场景:用户名,密码保存到cookie,(记住密码)
提供方法: getName() getValue()
案例:记住密码
当用户登录页面, 勾选记住密码, 登录, 登录成功之后, 下一次再登录, 显示上一次登录的用户名和密码
思路:
LoginServlet:
- 判断是否登录成功
- 登录成功之后, 判断是否勾选"记住我"
- 如果勾选, 把用户名,密码保存到cookie,
- 如果没有勾选: 判断是否有用户名,密码的cookie, 如果有,就删除
login.jsp:
用户名,密码的表单值获取cookie的值,动态显示
<%= %> 往页面输出内容: 缺点:如果内容为null, 也会在页面显示
替换<%= %>, 使用EL表达式 : ${域中的属性名}
从全域获取数据
${域中的属性名}
全域查找: 首先从page域查找,如果找到,直接返回
如果没找到, 从request查找, 如果找到,直接返回
如果没找到, 从session查找, 如果找到,直接返回
如果没找到, 从application查找, 如果找到,直接返回
如果没找到: 直接返回null
如果el表达式的结果为null, 在页面不展示
EL表达式支持 对象导航语言: ${对象.属性名..}
**前提:**域中存了user对象
java操作cookie:
服务器这边: 创建cookie: 构造方法 Cookie(String name,String value)
保存到客户端的方法: response对象的方法: addCookie(Cookie)
如果没有addCookie(), 那这个cookie不会保存到客户端
服务器获取cookie:
cookie是通过请求头传递到服务器:
request对象的Cookie[] getCookies()
Cookie的细节
-
Cookie的max-age
max-age: cookie最大存活时间 Cookie的setMaxAge(int )
默认值: -1 在会话中存活, 打开浏览器到关闭浏览器,称为一次会话
> 0
Cookie存活数值(秒)时间, 时间一到, 浏览器把cookie删除0: 立即删除Cookie
-
Cookie的path
设置Cookie的path, 限制那些资源允许访问
资源的上级目录下的cookie可以访问
资源的上上级目录的cookie可以访问
…
/目录下Cookie可以访问.
Cookie的path设置为/ ,表示该cookie可以被这个项目的所有的资源访问
-
修改Cookie的value
调用Cookie的setValue()
隐形修改:
Cookie c2 = new Cookie(“name”,“wangwu”)
如果客户端浏览器存在该key的cookie,并且path一样, 修改cookie的值
如果客户端浏览器不存在该key的cookie, 添加
如果客户端浏览器存在该key的cookie,但是path不一样, 添加
Cookie存放中文:
tomcat7之后可以存储了,不需要考虑
tomcat7以及之前的, Cookie不能存储中文, 需要把中文使用url编码
UTF-8: 中文(占3个字节): %两位十六进制%两位十六进制%两位十六进制
String str ="中国"; //URL编码 String str1 = URLEncoder.encode(str, "UTF-8"); System.out.println(str1);//%E4%B8%AD%E5%9B%BD //URL解码 String str2 = URLDecoder.decode(str1, "UTF-8"); System.out.println(str2);//中国
Tomcat8以及之后, Cookie支持中文, 如果有特殊符号, 不能存储, 借助url编码
HttpSession
主要作用:
实现一次会话多次请求之间数据的共享
一次会话的范围:
从打开浏览器访问服务器开始, 到关闭浏览器
使用Session
1.得到HttpSession对象 request.getSession() ; request.getSession(boolean)
getSession(): 如果当前请求有session,返回当前请求session的对象, 如果没有,创建一个新的session对象
getSession(boolean create):
true: 与getSession() 一样,
false: 如果当前请求有session,返回当前请求session的对象,如果没有, 返回null
2.删除Session void invalidate()
让session失效, 这个session无效, session中存储的数据都失效
3.设置session最大存活时间 void setMaxInactiveInterval(int interval) 单位:秒
Session默认的存放时间:
30分钟, 从上一次请求到下一次请求之间超过30分钟, session被服务器删除(Tomcat维护一个session池)
Session的特征
创建于服务器, 保存于服务器
Session实现原理 面试题
服务器会为用户创建一个Session对象,并且把sessionId 以cookie的形式,保存在客户端浏览器上, 用户之后每次请求, 自动把cookie(JSESSIONID) 带回到服务器, 服务器根据sessionId匹配session池的对应的session的对象, 服务器知道当前请求是哪个会话的(来自哪个浏览器),
如果客户端的cookie被删除, 请求不会带JSessionId, 服务器就不知道哪个Session是这个用户的(浏览器的), 之前的为该用户创建的session,谁也无法访问,就是个垃圾,服务器默认30分钟之后删除这个session,
如果服务器把session删除, 就算客户端有JSessionid的Cookie, 也无法得到Session, 服务器会为浏览器重新创建Session,并新的sessionId以Cookie的形式保存客户端
案例:退出登录
1.点击退出按钮,发送请求到LogoutServlet
2.让session失效
3.重定向到login.jsp
案例:验证码的实现
生成验证码的servet将生成的验证码预先存储在session
request.getSession().setAttribute("CHECKCODE_SERVER",checkCode);
1.用户填写验证码,点击登录,发送登录请求LoginServlet
2.判断验证码是否正确
3.不正确:直接响应“验证码错误”,转发到login.jsp
4.正确:重定向到index.jsp
案例:点击刷新验证码
<a href="javascript:;" onclick="refreshCode()" >
<img src="${pageContext.request.contextPath}/checkCodeServlet" title="看不清点击刷新" id="vcode"/>
</a>
另一种写法
<a href="javascript:refreshCode();">
<img src="${pageContext.request.contextPath}/checkCodeServlet" title="看不清点击刷新" id="vcode"/>
</a>
点击a标签后调用函数,点击a标签触发href里的地址,执行js
//切换验证码
function refreshCode(){
//1.获取验证码图片对象
var vcode = document.getElementById("vcode");
//2.设置其src属性,加时间戳
vcode.src = "${pageContext.request.contextPath}/checkCodeServlet?time="+new Date().getTime();
}
为什么加时间戳
防止浏览器缓存,如果地址栏不改变,服务器会认为没有发起新的请求,通过缓存展示上一次的资源,验证码也就不会更新
MVC
MVC是一种**软件架构模式,**这种模式把项目分为三大模块:
M: model 模型层: pojo, dao
C: controller 控制层: Servlet
V: view 视图层: jsp,html
java中视图层和模型层不能直接访问
javaWeb开发
经典三层模型, java类的分层概念
接收用户请求的角色: web层
处理业务逻辑的角色: service层
与数据库通信的角色: dao层
分层目的:技术隔离
比如dao层使用到的技术,只能在dao层存在, 不能延伸到其他
好处: 项目扩展时, 需要替换某一层的技术,只需要更换这一层,其他层不需要改变
注意事项:
- 跨层调用, 调用顺序: web层调用->service层调用->dao层
- 只能上层调用下层, web调用service, service调用到dao, 不能下层调用上层
- 层与层使用接口隔离, service:提供接口, 让web使用, dao层提供接口,让service使用
JSTL标签 (了解)
**作用:**替换Java脚本,通常和EL表达式一起使用
在服务器端执行, 把jstl执行之后的结果响应给客户端浏览器,JSTL标签在Html标签之前执行
使用步骤:
1.导入支持JSTL的依赖
2.在使用jstl标签的jsp页面, 使用 taglib指令,导入标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
prefix: 前缀, 任意取名, 规范名: c (core标签库): 比如:
<c:div>
使用前缀区分html标签core所有的标签名:
<c:标签名>
uri: 对应jstl标签的url, 固定写法, 导入jstl标签库, 选择的是 jsp/jstl的标签库
3.使用JSTL标签
常见JSTL标签
(1)<c:if test=“条件”> </c:if>>
(没有else标签,没有else if标签)
(2)choose标签
<c:choose>
<c:when test="${score >= 90}">
<p>优秀</p>
</c:when>
<c:when test="${score >= 80}">
<p>良好</p>
</c:when>
<c:when test="${score >= 60}">
<p>及格</p>
</c:when>
<c:otherwise>
<p>不及格</p>
</c:otherwise>
</c:choose>
(3)foreach标签: for循环
for i
<c:forEach var="i" begin="0" end="9" step="2">
<h1>${i}</h1>
</c:forEach>
增强for循环:
<c:forEach var="admin" items="${admins}">
<tr>
<th>${admin.id}</th>
<th>${admin.username}</th>
<th>${admin.password}</th>
</tr>
</c:forEach>
forEach循环 有一个varStatus=“变量” , 得到for循环的循环状态对象
forEach标签还有一个属性:varStatus,这个属性用来指定接收“循环状态”的变量名,例如:<forEach varStatus=”vs” …/>,这时就可以使用vs这个变量来获取循环的状态了。
vs的取值可以是:
- count:int类型,当前已经遍历元素的个数(序号); 第几次循环,从1开始
- index:int类型,当前元素的下标; 从0开始
- first:boolean类型,是否为第一个元素;
- last:boolean类型,是否为最后一个元素;