服务器Servlet
本篇三部分:
一、web开发入门 (http协议)
二、Servlet和ServletConfig
三、request、response
四、cookie、session
一、web开发
1.web开发先看看有哪些web 相关技术:
静态web技术:html
动态web技术:JSP/Servlet、ASP、PHP
2.web资源访问流程:
文字概述:
1.询问本机window中host得到网址IP 2.没有从host中得到的话就会再从DNS解析域名成IP 3.得到IP后连接网站服务器端 4.连接后发送http请求 5.服务器从http请求中得到客户机想要访问的主机名以及想访问的应用和资源 6.从而读取相应主机的web应用和web资源 (得到html) 7.读取资源并回应http响应到服务器端 8.服务器端发送http响应至浏览器 9.浏览器解析响应
图解: (补充: DNS:解析域名成IP地址。 TCP协议:验证传输 。IP协议:地址)
3.http协议:
(1)概述:
http:是超文本传输协议 ,是TCP/IP协议上的应用层协议
a. 用于定义web浏览器与web服务器间的交换数据的过程。是客户端和服务器交互的一种通迅的格式
b.HTTP是无状态的,也就是说,它是不对通信状态进行保存的。它并不知道之前通信的对方是谁。这样设计的目的就是为了让HTTP简单化,能够快速处理大量的事务!
c.一次HTTP连接能够处理多个请求。在一次HTTP连接里面,不需要等待服务器响应请求,就能够继续发送第二次请求。
d.常用的HTTP方法 post/get(请求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT)
(2)http请求
格式: a.请求行 (GET是默认方式,加?会在连接上显示数据,但get方式带的容量有限不能超过1K,而post方式无限量)
b.多个请求头(host,cookie,,,)
c.空行
d.请求数据
(3)http响应
代表服务器向客户端回送的数据
格式: 状态行 (有状态码)
多个响应头
一个空行
实体
(4).常用的状态码
2XX :一般是请求成功 200 正常处理 204 成功处理,但服务器没有新数据返回,显示页面不更新 206 对服务器进行范围请求,只返回一部分数据
3XX :一般表示重定向 301 请求的资源已分配了新的URI中,URL地址改变了。【永久重定向】 302 请求的资源临时分配了新的URI中,URL地址没变【转发】 303 与302相同的功能,但明确客户端应该采用GET方式来获取资源 304 发送了附带请求,但不符合条件【返回未过期的缓存数据】 307 与302相同,但不会把POST请求变成GET
4XX :表示客户端出错了。 400 请求报文语法错误了 401 需要认证身份 403 没有权限访问 404 服务器没有这个资源
5XX :服务器出错了 500 内部资源出错了 503 服务器正忙
(5).Https:
https: http是不安全的,使用SSL建立安全的通信线路,HTTPS就是披着SSL的HTTP。
Http与Https的区别:
(1)写法:HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
(2)安全性:HTTP 是不安全的,而 HTTPS 是安全的
(3)端口:HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
(4)工作层:在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
(5)加密性:HTTP 无法加密,而HTTPS 对传输的数据进行加密
(6)证书:HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
(6).URI和URL的区别
URI:是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。它唯一的作用就是解析
URL:是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。URL类可以打开一个到达资源的流。
二、Servlet和ServletConfig
1.Servlet
(1)作用
Servlet:动态WEB技术,就是能够处理浏览器带来HTTP请求,并返回一个响应给浏览器,从而实现浏览器和服务器的交互。
(2)servlet线程安全问题
是不安全的。
线程安全问题 当多个用户访问Servlet的时候,服务器会为每个用户创建一个线程。当多个用户并发访问Servlet共享资源的时候就会出现线程安全问题。
(3)生命周期
- 加载Servlet。当Tomcat第一次访问Servlet的时候,Tomcat会负责创建Servlet的实例
- 初始化。当Servlet被实例化后,Tomcat会调用init()方法初始化这个对象
- 处理服务。当浏览器访问Servlet的时候,Servlet 会调用service()方法处理请求
- 销毁。当Tomcat关闭时或者检测到Servlet要从Tomcat删除的时候会自动调用destroy()方法,让该实例释放掉所占的资源。一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁
- 卸载。当Servlet调用完destroy()方法后,等待垃圾回收。如果有需要再次使用这个Servlet,会重新调用init()方法进行初始化操作。
- 简单总结:**只要访问Servlet,service()就会被调用。init()只有第一次访问Servlet的时候才会被调用。
(4)
为什么Servlet是单例的
浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭。
(5)
线程安全问题
当多个用户访问Servlet的时候,服务器会为每个用户创建一个线程。当多个用户并发访问Servlet共享资源的时候就会出现线程安全问题。
原则:
- 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (对象){}
- 如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题
(6)缺省Servlet
2.ServletConfig
通过此对象可以读取web.xml中配置的初始化参数。
(1)获取方法:
this.getServletContext();
3.ServletContext 域
全局域对象 代表着当前web站点 (一个容器)
获取:ServletContext context= (ServletContext) this.getServletContext();
作用:ServletContext可以获取的是配置整个web站点的参数信息 所有Servlet都共享着一个ServletContext对象,所以Servlet之间可以通过ServletContext实现通讯。 实现servlet的转发 利用servletContext对象读取资源文件。
方法:ServletContext的setAttribute(String name,Object obj)方法
//获取到ServletContext对象 ServletContext servletContext = this.getServletContext(); String value = "zhongfucheng"; //MyName作为关键字,value作为值存进 域对象【类型于Map集合】 servletContext.setAttribute("MyName", value);
4.HttpServlet类
处理HTTP请求的servlet
实现HttpServlet
三、request、response
什么是HttpServletResponse对象?
http响应由状态行、实体内容、消息头、一个空行组成。HttpServletResponse对象就封装了http响应的信息。
1.response 应用案例
向浏览器输出数据,找response对象
(1)response写出数据:
response.setContentType("text/html;charset=UTF-8");
//获取到printWriter对象
PrintWriter printWriter = response.getWriter(); printWriter.write("看完博客点赞!");
(2)response实现下载文件
String path= this.getServletContext().getRealPath("/download/环奈.jpg");
//截取文件名方法 substring(path.lastIndexOf("\\")+1) String filename =path.substring(path.lastIndexOf("\\")+1); //打开方式 response.setHeader("content-disposition", "attachment;filename"+URLEncoder.encode(filename,"UTF-8")); //这两行代码作用就是为了提供给下载功能,去掉后则直接是显示图片 //通过流写数据 InputStream in = null; OutputStream out = null; try { in = new FileInputStream(path); int len = 0; byte[] buffer = new byte[1024]; out = response.getOutputStream();//修改 while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } }finally { if (in != null) { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (Exception e) { e.printStackTrace(); } } } }
(3)servlet方法的验证码 ,随机生成图片
BufferedImage image = new BufferedImage(WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB); Graphics g=image.getGraphics(); //1.设置背景色 setBackGround(g); //2.设置边框 setBorder(g); //3.设置干扰线 drawRandomLine(g); //4.写随机数 drawRandomNum(g); //5.图形写给浏览器 response.setContentType("image/jpeg"); //去掉缓存,即更新 response.setHeader("Cache-Content", "no-cache"); response.setHeader("Pragma", "no-cache"); ImageIO.write(image, "jpg", response.getOutputStream()); } //设置背景色 private void setBackGround(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, WIDTH, HEIGHT); } //设置边框 private void setBorder(Graphics g) { g.setColor(Color.BLUE); g.drawRect(1, 1, WIDTH-2, HEIGHT-2); } //设置干扰线 private void drawRandomLine(Graphics g) { g.setColor(Color.GREEN); for(int i=0;i<5;i++){ //设置五条干扰线 int x1=new Random().nextInt(WIDTH); int y1=new Random().nextInt(HEIGHT); int x2=new Random().nextInt(WIDTH); int y2=new Random().nextInt(HEIGHT); g.drawLine(x1, y1, x2, y2); //做线 } } //写随机数 private void drawRandomNum(Graphics g) { g.setColor(Color.RED); g.setFont(new Font("宋体",Font.BOLD,20)); String base="\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a"; StringBuffer sb=new StringBuffer(); int x=0; for(int i=0;i<4;i++){ int degree=new Random().nextInt(30); String ch=base.charAt(new Random().nextInt(base.length()))+""; sb.append(ch);// // 写入字之前,设置好旋转// g.rotate(degree*Math.PI/180, x, 20); // 设置字体旋转角度// g.drawString(ch, x, 20);// // 这次旋转不能影响下一次的旋转,所以要将上一次的旋转清掉,转回去 g.drawString(ch, x, 30); x+=50; } }
(4).定时刷新,转发
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("3秒后跳转页面....."); //三秒后跳转到index.jsp页面去,web应用的映射路径我设置成/,url没有写上应用名
response.setHeader("Refresh", "3;url='/index.jsp'");
(5)response 请求重定向
例如:response.sendRedirect("/WEB2/index.jsp");
2.request 应用案例
获取浏览器提交过来的数据,找request对象
(1)HttpServletRequest:
要得到浏览器信息,就找HttpServletRequest对象
HttpServletRequest常用方法
.获得客户机【浏览器】信息getRequestURL方法返回客户端发出请求时的完整URL。getRequestURI方法返回请求行中的资源名部分。getQueryString 方法返回请求行中的参数部分。getPathInfo方法返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。getRemoteAddr方法返回发出请求的客户机的IP地址getRemoteHost方法返回发出请求的客户机的完整主机名getRemotePort方法返回客户机所使用的网络端口号getLocalAddr方法返回WEB服务器的IP地址。getLocalName方法返回WEB服务器的主机名
.获得客户机请求头
getHeader方法getHeaders方法getHeaderNames方法
.获得客户机请求参数(客户端提交的数据)
getParameter方法getParameterValues(String name)方法getParameterNames方法getParameterMap方法
(2) request转发
使用response的sendRedirect()可以实现重定向,做到的功能是页面跳转,
使用request的getRequestDispatcher.forward(request,response)实现转发,做到的功能也是页面跳转
//获取到requestDispatcher对象,跳转到index.jsp
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.jsp");
//调用requestDispatcher对象的forward()实现转发,传入request和response方法
requestDispatcher.forward(request, response);
(3)中文乱码
post方式直接改request对象的编码
get方式需要手工转换编码get方式也可以修改Tomcat服务器的编码,不推荐,因为会太依赖服务器了!提交数据能用post就用postrequest.setCharacterEncoding("UTF-8");
(4)防盗链(设计网投、网尾)
例子:
//获取到网页是从哪里来的 String referer = request.getHeader("Referer"); //如果不是从我的首页来或者从地址栏直接访问的, if ( referer == null || !referer.contains("localhost:8080/zhongfucheng/index.jsp") ) { //回到首页去 response.sendRedirect("/zhongfucheng/index.jsp"); return; } //能执行下面的语句,说明是从我的首页点击进来的,那没问题,照常显示 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("路飞做了XXXXxxxxxxxxxxxxxxxx");
3.补充
(1)转发和重定向的区别
实际发生位置不同,地址栏不同
转发是发生在服务器的,
实现转发只是一次的http请求,一次转发中request和response对象都是同一个。这也解释了,为什么可以使用request作为域对象进行Servlet之间的通讯。重定向是发生在浏览器的重定向是由浏览器进行跳转的,进行重定向跳转的时候,浏览器的地址会发生变化的。曾经介绍过:实现重定向的原理是由response的状态码和Location头组合而实现的。这是由浏览器进行的页面跳转实现重定向会发出两个http请求,**request域对象是无效的,因为它不是同一个request对象
用法不同:
给服务器用的直接从资源名开始写,给浏览器用的要把应用名写上request.getRequestDispatcher("/资源名 URI").forward(request,response)转发时"/"代表的是本应用程序的根目录
response.send("/web应用/资源名 URI");重定向时"/"代表的是webapps目录
典型的应用场景:
转发: 访问 Servlet 处理业务逻辑,然后 forward 到 jsp 显示处理结果,浏览器里 URL 不变
重定向: 提交表单,处理成功后 redirect 到另一个 jsp,防止表单重复提交,浏览器里 URL 变了
重定向特点:
1.浏览器会向服务器发送两次,意味这有两个request/response
2.重定向技术会让浏览器地址发生变化3.response 中getOutStream()和getWrite()不能同时用
重定向与请求转发使用
前后两个页面 有数据传递 用请求转发,没有则用重定向。
重定向时的网址可以是任何网址
转发的网址必须是本站点的网址
四、cookie、session
会话:访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话.
保存会话数据的两种技术:
Cookie 客户端技术Sesssion 服务端技术
区别:
cookie是把用户的数据写给用户的浏览器 session技术是把用户的数据写到用户独占的seesion中
1.Cookie
流程:浏览器访问服务器,如果服务器需要记录该用户的状态,就使用response向浏览器发送一个Cookie,浏览器会把Cookie保存起来。当浏览器再次访问服务器的时候,浏览器会把请求的网址连同Cookie一同交给服务器。
常用的Cookie方法:
public Cookie(String name,String value)setValue与getValue方法setMaxAge与getMaxAge方法setPath与getPath方法setDomain与getDomain方法getName方法
2.设置时间
没有设置有效期那么浏览器关闭cookie数据消 ,不设置时间不会显示cookie文本
Cookie的有效期是通过setMaxAge()来设置的。cookie.setMaxAge(1000);
如果MaxAge为正数,浏览器会把Cookie写到硬盘中,只要还在MaxAge秒之前,登陆网站时该Cookie就有效【不论关闭了浏览器还是电脑】
如果MaxAge为负数,**Cookie是临时性的,仅在本浏览器内有效,关闭浏览器Cookie就失效了,Cookie不会写到硬盘中。Cookie默认值就是-1。如果MaxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie对应的方法,把MaxAge设置为0等同于删除Cookie
案例:
response.setContentType("text/html;charset=UTF-8"); PrintWriter printWriter = response.getWriter(); String name = "看完博客就点赞"; //对Unicode字符进行编码 Cookie cookie = new Cookie("country", URLEncoder.encode(name, "UTF-8")); //一定不要忘记添加到浏览器中 cookie.setMaxAge(0); response.addCookie(cookie); printWriter.write("我删除了该Cookie");
3.每个cookie的大小限制为4kB
4.Cookie具有不可跨域名性:所以一般来说,当我访问baidu的时候,浏览器只会把baidu颁发的Cookie带过去,而不会带上google的Cookie。
5.显示上次时间
案例:
// 防止乱码
response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");// 建立输出流
PrintWriter out = response.getWriter(); out.print("上次访问时间: <br/>");// 获取COOKIE时间
Cookie[] cookies = request.getCookies(); for (int i = 0; cookies != null && i < cookies.length; i++) { if (cookies[i].getName().equals("lastAccessTime")) { long cookiesvalue = Long.parseLong(cookies[i].getValue());Date date = new Date(cookiesvalue);
out.print(date.toLocaleString()); } } // 数据发送到浏览器并设置 Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis() + ""); cookie.setMaxAge(1 * 30 * 24 * 3600); cookie.setPath("/WEB3"); response.addCookie(cookie);
2.Sesssion
一个浏览器独占一个session对象
session由服务器创建,开发人员调用request对象的getsession方法得到session对象
Session比Cookie使用方便,Session可以解决Cookie解决不了的事情 :Session可以存储对象,Cookie只能存储字符串
周期: 创建session,不管浏览器是否关闭,在三十分钟后自动摧毁session。
session原理:request.getSession()方法创建session,同时生成sessionId,cokkie带sessionId返回浏览器保存,下次浏览器访问时根据id调用对应的seesion
(所以说sessin是基于cookie)
1.Session API:
long getCreationTime();【获取Session被创建时间】
String getId();【获取Session的id】long getLastAccessedTime();【返回Session最后活跃的时间】ServletContext getServletContext();【获取ServletContext对象】void setMaxInactiveInterval(int var1);【设置Session超时时间】int getMaxInactiveInterval();【获取Session超时时间】Object getAttribute(String var1);【获取Session属性】Enumeration getAttributeNames();【获取Session所有的属性名】void setAttribute(String var1, Object var2);【设置Session属性】void removeAttribute(String var1);【移除Session属性】void invalidate();【销毁该Session】boolean isNew();【该Session是否为新的】
2.案例1:用户登录
3.案例2:防止表单重复提交
4.当禁用cookie时,用URL重写实现session
URL地址重写的原理:将Session的id信息重写到URL地址中。服务器解析重写后URL,获取Session的id。这样一来,即使浏览器禁用掉了Cookie,但Session的id通过服务器端传递,还是可以使用Session来记录用户的状态。
Session和Cookie的区别
1.存储方式上比较
Cookie只能存储字符串,如果要存储非ASCII字符串还要对其编码。Session可以存储任何类型的数据,可以把Session看成是一个容器2.从隐私安全上比较
Cookie存储在浏览器中,对客户端是可见的。信息容易泄露出去。如果使用Cookie,最好将Cookie加密Session存储在服务器上,对客户端是透明的。不存在敏感信息泄露问题3.从对服务器的负担比较
Session是保存在服务器的,每个用户都会产生一个Session,如果是并发访问的用户非常多,是不能使用Session的,Session会消耗大量的内存。Cookie是保存在客户端的。不占用服务器的资源。像baidu、Sina这样的大型网站,一般都是使用Cookie来进行会话跟踪4.从跨域名上比较
Cookie可以设置domain属性来实现跨域名Session只在当前的域名内有效,不可夸域名5.cookie是吧数据写到浏览器
session是把数据写到用户独立的session中
(*)四个域对象session(session域)、servletContext(application域)、request(reqeust域)、pageContext(page域)
request容器:当程序产生数据后如果显示后没有用了就用requst,一次请求
session:产生数据后除了显示等一会要用到则session,一次会话servletContext:不仅等一会还要给别人用(例如聊天室),整个web应用pageContext(page域):当前Jsp页面范围