Servlet基础

来源:互联网 发布:哈佛大学医学院 知乎 编辑:程序博客网 时间:2024/06/11 19:07

Servlet的基础概念

Servlet是SUN提供的一门用于开发动态WEB资源的技术。

在白板中编译运行Servlet程序,需要把Servlet的jar包(class文件)加到classpath中。

命令:javac -d . FirstServlet.java,-d表示要编译的java文件带包,.表示把编译后的class文件保存在当前目录中。

Servlet的调用过程和生命周期

  1. 浏览器连上了WEB服务器;
  2. 浏览器发送HTTP请求;
  3. WEB服务器解析出请求中要访问的主机名;
  4. 解析出请求中要访问的WEB应用;
  5. 解析出请求中要访问的WEB资源;
  6. 第一次访问Servlet,Servlet对象实例化,Servlet对象仅创建一次;
  7. 调用servlet的init方法完成对象初始化;
  8. 创建代表请求request和代表响应的response,调用Servlet的service方法响应客户端的请求;
  9. service方法执行;
  10. service方法返回;
  11. 服务器从response中取出数据,构建出一个HTTP响应,回写给客户端;
  12. 回写HTTP响应;
  13. 浏览器解析HTTP响应,提取数据显示;

web.xml的有关配置

同一个Servlet可以被映射到多个URL上。

<load-on-startup>1</load-on-startup>让servlet在服务器启动的时候初始化。数字越小,启动优先级越高

如果某个Servlet的映射路径仅仅为一个正斜杠/,那么这个Servlet就成为当前web应用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的元素的URL,他们的访问请求都交给缺省Servlet处理。

ServletConfig对象

在servlet的配置文件(web.xml)中,可以使用一个或多个标签为servlet配置一些初始化参数。

当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到servletConfig对象中,并在调用servlet的init方法时,将servletConfig对象传递给servlet。进而,程序员通过servletconfig对象就可以得到当前servlet的初始化参数信息。

在实际开发中,有一些数据不适合在servlet程序中写死,这类数据可以通过配置方式配给servlet。例,servlet采用什么码表、servlet连接哪个数据库。

ServletContext对象

web容器在启动时,它会为每个web应用程序都创建一个对应的ServletContext对象,它代表当前web应用,web服务器关闭或删除web应用时,会销毁相应的ServletContext对象。

ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。

由于一个web应用中的所有servlet共享同一个servletcontext对象,所以多个servlet通过servletcontext对象实现数据共享。servletcontext对象通常也被称之为context域对象。也可以利用ServletContext实现Servlet的转发。

在web.xml中用初始化web应用的参数(Servlet共享)。

HttpServletResponse:响应对象

通过response的字节流输出数据常见问题

  1. 数据以什么编码输出,程序就一定要控制浏览器以什么编码打开
response.setHeader("Content-type","text/html;charset=UTF-8");String data="中国";OutputStream out=response.getOutputStream();out.write(data.getBytes("UTF-8"));
  1. 用html中meta标签模拟了一个http响应头,来控制浏览器的行为
out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>");

通过response的字符流输出数据常见问题

  1. 设置response使用的编码,以控制response以什么编码向浏览器写出数据response.setCharacterEncoding("UTF-8");
  2. 指定浏览器以什么码表打开服务器发送的数据
response.setHeader("content-type","text/html;charset=UTF-8");String data="中国";PrintWriter out=response.getWriter();out.write(data);
  1. 相当于以上两个操作的代码response.setContentType("text/html;charset=UTF-8");

response实现文件下载

String path=this.getServletContext().getRealpath("/download/1.jpg");String filename=path.substring(path.lastIndexof("\\"+1));response.setHeader("content-disposition","attachment;filename="+filename);//中文会有乱码response.setHeader("content-disposition","attachment;filename="+URLEncoder.encode(filename,"UTF-8"));//无乱码InputStream in=new FileInputStream(path);OutputStream out=response.getOutputStream();

response输出随机认证图片

BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);Grahics g=image.getGrahics();//设置背景色g.setColor(Color.WHITE);g.fillRect(0,0,WIDTH,HEIGHT);//设置边框g.setColor(Color.BULE);g.drawRect(1,1,WIDTH-2,HEIGHT-2);//画干扰线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);}//写随机数String base="\u7684\u4e00"g.setColor(Color.RED);g.setFont(new Font("宋体",Font.BOLD,20));int x=10;for(int i=0;i<4;i++){    int degree=new Random().nextInt()%30;    String ch=base.chatAt(new Random().nextInt(Base.length())+"");    g.rotate(degree*Math.PI/180,x,20);---Graphics2D,设置旋转角度。    g.drawsString(ch,x,20);    g.rotate(-degree*Math.PI/180,x,20);    x+=30;}//图形写给浏览器response.setContentType("image/jpeg");response.setDateHeader("expries",-1);response.setHeader("Cache-Control","no-cache");response.setHeader("Pragma","no-cache");ImageIO.write(image,"jpg",response.getOutputStream());//javascript编码换一张页面图片。<img src="..." onclick="changImage(this)" alt="换一张" style="cursor:hand"><script type="text/javascript">    function changeImage(img){        img.src=img.src+"?"+new Date().getTime();//不加上随机数,浏览器会直接拿缓冲。    }</script>

控制浏览器定时刷新

response.setHeader("refresh","3");

实用的自动跳转技术

String message="<meta http-equiv='refresh' content='3' url=...>something";this.getServletContext().setAttribute("message",message);this.getServletContext().getRequestDispatcher("/message.jsp").forward(request,response);

用Expires头控制浏览器缓存

response.setDateHeader("expires",System.currentTimeMillis()+1000*3600);

实现请求重定向

response.setStaus(302);response.setHeader("location","/index.jsp");response.sendRedirect(/index.jsp);//该操作包含以上两个操作

重定向的特点:
1.浏览器会向服务器发送两次请求。
2.浏览器地址栏会发生变化。

HttpServletRequest:请求对象

URI-/news/1.html
URL-http://www.sina.com/news/1.html
URI的范围比URL大。URI包括URL

获得客户端的信息
- getRequestURL方法返回客户端发出请求时的完整URL。
- getRequestURI方法返回请求行中的资源名部分。
- getQueryString方法返回发出请求行中的参数部分。
- getRemoteAddr方法返回发出请求的客户机的IP地址。
- getRemoteHost方法返回发出请求的客户机的完整主机名。
- getRemotePort方法返回客户机所使用的网络端口号。
- getLocalAddr方法返回web服务器的IP地址。
- getLocalName方法返回web服务器的主机名。
- getMethod方法得到客户机的请求方式。

获取多个同名参数

String[] values=request.getParameterValues("username");for(int i=0;values!=null&&i<values.length;i++){    System.out.println(values[i]);}

获取数据时,一般要先检查数据是否合法

if(value!=null&&!value.tirm().equals("")){}

获取数据,再封装成对象

Map<String,String[]> map=request.getParameterMap();User user=new User();BeanUtils.populate(user,map);需要导入BeanUtil的jar包。

request中文乱码

request.setCharacterEncoding("utf-8");要在request获取参数之前设置request的码表。这种方式只对post有效。
对get有效的解决方案:

String username=request.getparameter("username");username=new String(username.getBytes("iso8859-1"),"utf-8");

使用request域对象把数据带给转发资源

String data="s";request.setAttribute("data",data);request.getRequestDispatcher("/message.jsp").forward(request,response);

把response的输出流close之后,就会对浏览器作出响应。响应之后不能将请求转发,否则会抛异常。每次响应后,应该return。
forward时,会清空response中的数据。

请求转发的特点:
1. 客户端只发一次请求,而服务器端有多个资源调用。
2. 客户端浏览地址栏没有变化。

web工程中各类地址的写法:
1. 地址给服务器用,/代表当前web应用。
2. 地址给浏览器用的,/代表网站,网站下有多个web应用。

referer防盗链

String referer=request.getHeader("referer");if(referer==null||referer.startsWith("http://localhost")){    response.sendRedirect("/test/index.jsp");    return;}   

会话

用户打开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。

Cookie

Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器,并存在本地硬盘中。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

Cookie类用于创建一个Cookie,response接口中也定义了一个addCookie方法,它用于在其响应头中增加一个相应的Set-Cookie头字段。同样,request接口中也定义了一个getCookie方法,它用于获取客户端提交的Cookie。

Cookie常用API

  • public Cookie(String name,String value)
  • setValue(),getValue()
  • setMaxAge(),getMaxAge();如果不设置MaxAge,关闭浏览器Cookie就会失效。设置值为0,则将cookie失效,删除cookie时,path必须一致,否则不会删除。
  • setPath(),getPath();Cookie的有效路径。默认的路径是发出Cookie的servlet所在的目录。
  • setDomain(),getDomain();
  • getName();

Session

Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的session中取出数据为用户服务。

Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。

第一个访问getSession()方法时,服务器才为浏览器创建session。关闭浏览器后,session并没有马上消失,session创建30分钟后自动消失。在web.xml中可以配置session的失效时间。也可以在程序中用session.invalidate()让session失效。getSession(false):获取session,不创建session。

Session和Cookie的主要区别

Cookie是把用户的数据写给用户的浏览器。

Session技术把用户的数据写到用户独占的session中。

Session与Cookie的联系
session是基于cookie的,session的id号已cookie的形式回写给浏览器,浏览器的下次访问会带着cookie形式的sessionID号来,服务器根据session的ID号来区分拿哪个session来服务。这个回写的cookie并没有设置有效期,所以想要闭关浏览器后session可用,可以新建一个cookie来覆盖session回写的cookie,再设置cookie有效期。

URL重写

用户的浏览器如果禁用了cookie,那就在超链接中附上session的id号实现保存用户数据的功能,这叫做URL重写。

response.encodeURL(),这个方法用于把地址加上session的id号。

如果用了URL重写,浏览器的cookie又没有禁用,服务器第一次发现浏览器带着cookie来访问时,URL上会写有sessionID号,但是服务器第二次发现浏览器带着cookie来访问时,就会把URL重写中的sessionID号去掉。

配置文件

数据之间没关系的用properties文件。
数据之间有关系的用xml文件。

读取properties文件中的资源

InputStream in=this.getServletContext().getResourceAsStream("/WEB-INF/class/db.properties");Properties props=new Property();props.load(in);//底层通过map集合存数据。String url=props.getProperty("url");

通过servletContext的getRealPath得到资源的绝对路径,再通过传统资源读取资源文件。

String path=this.getServletContext().getRealPath("/WEB-INF/class/db.properties");FileInputStream in=new FileInputStream(path);

如果读取资源文件的程序不是servlet的话,就只能通过类装载器去读了,这种方式资源文件不能太大。

Person.class.getClassLoader().getResourceAsStream("db.properties");

如果web应用中的资源文件更新,这样通过类装载类读取文件的方式,不能读取到更新后的资源文件,因为类装载器在web服务器启动时只装载一次。

通过类装载的方式得到资源文件的位置,再通过传统方式读取资源文件的数据,这样可以读取到更新后的数据。

String path=Person.class.getClassLoader().getResource("db.properties").getPath();FileInputStream in=new FileInputStream(path);Properties dbconfig=new Properties();dbconfig.load(in);
原创粉丝点击