Servlet是一个Java程序,是在服务器上运行以处理客户端请求并做出响应的程序。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
- 1、编写一个Java类,实现servlet接口。
- 2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet。
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
实例化:Servlet容器创建Servlet的实例 初始:该容器调用inint()方法 请求处理:如果请求Servlet,则容器调用Service()方法
在Servlet初始化过程中获取配置信息
一个Servlet只有一个ServletConfig对象
ServletConfig接口的常用方法:
ServletContext接口:获取上下文信息
ServletContext就是jsp内置对象application的原类型。
使用doXxx()接收用户请求
doGet():用户使用get方式提交请求时调用
doPost():用户使用posy方式提交请求时调用
HttpServletResponse对象代表服务器的响应。这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。查看HttpServletResponse的API,可以看到这些相关的方法。
使用OutputStream流输出中文注意问题:
在服务器端,数据是以哪个码表输出的,那么就要控制客户端浏览器以相应的码表打开,比如:outputStream.write(“中国”.getBytes(“UTF-8”));使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出,此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码,那么在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢?可以通过设置响应头控制浏览器的行为,例如:response.setHeader(“content-type”, “text/html;charset=UTF-8”);通过设置响应头控制浏览器以UTF-8的编码显示数据。
25 public void outputChineseByOutputStream(HttpServletResponse response) throws IOException{ 26 /**使用OutputStream输出中文注意问题: 27 * 在服务器端,数据是以哪个码表输出的,那么就要控制客户端浏览器以相应的码表打开, 28 * 比如:outputStream.write("中国".getBytes("UTF-8"));//使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出 29 * 此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码,那么在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢? 30 * 可以通过设置响应头控制浏览器的行为,例如: 31 * response.setHeader("content-type", "text/html;charset=UTF-8");//通过设置响应头控制浏览器以UTF-8的编码显示数据 32 */ 33 String data = "中国"; 34 OutputStream outputStream = response.getOutputStream();//获取OutputStream输出流 35 response.setHeader("content-type", "text/html;charset=UTF-8");//通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码 36 /** 37 * data.getBytes()是一个将字符转换成字节数组的过程,这个过程中一定会去查码表, 38 * 如果是中文的操作系统环境,默认就是查找查GB2312的码表, 39 * 将字符转换成字节数组的过程就是将中文字符转换成GB2312的码表上对应的数字 40 * 比如: "中"在GB2312的码表上对应的数字是98 41 * "国"在GB2312的码表上对应的数字是99 42 */ 43 /** 44 * getBytes()方法如果不带参数,那么就会根据操作系统的语言环境来选择转换码表,如果是中文操作系统,那么就使用GB2312的码表 45 */ 46 byte[] dataByteArr = data.getBytes("UTF-8");//将字符转换成字节数组,指定以UTF-8编码进行转换 47 outputStream.write(dataByteArr);//使用OutputStream流向客户端输出字节数组 48 }
使用PrintWriter流输出中文注意问题:
在获取PrintWriter输出流之前首先使用”response.setCharacterEncoding(charset)”设置字符以什么样的编码输出到浏览器,如:response.setCharacterEncoding(“UTF-8”);设置将字符以”UTF-8”编码输出到客户端浏览器,然后再使用response.getWriter();获取PrintWriter输出流,这两个步骤不能颠倒,如下:
1 response.setCharacterEncoding("UTF-8");//设置将字符以"UTF-8"编码输出到客户端浏览器 2 /** 3 * PrintWriter out = response.getWriter();这句代码必须放在response.setCharacterEncoding("UTF-8");之后 4 * 否则response.setCharacterEncoding("UTF-8")这行代码的设置将无效,浏览器显示的时候还是乱码 5 */ 6 PrintWriter out = response.getWriter();//获取PrintWriter输出流
然后再使用response.setHeader(“content-type”, “text/html;charset=字符编码”);设置响应头,控制浏览器以指定的字符编码编码进行显示,例如:
1 //通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码 2 response.setHeader("content-type", "text/html;charset=UTF-8");
除了可以使用response.setHeader(“content-type”, “text/html;charset=字符编码”);设置响应头来控制浏览器以指定的字符编码编码进行显示这种方式之外,还可以用如下的方式来模拟响应头的作用
2 * 多学一招:使用HTML语言里面的<meta>标签来控制浏览器行为,模拟通过设置响应头控制浏览器行为 3 *response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>"); 4 * 等同于response.setHeader("content-type", "text/html;charset=UTF-8"); 5 */ 6 response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");
文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载。
文件下载功能的实现思路:
1 package gacl.response.study; 2 import java.io.FileInputStream; 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.OutputStream; 8 import java.io.PrintWriter; 9 import java.net.URLEncoder; 10 import javax.servlet.ServletException; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 /** 15 * @author gacl 16 * 文件下载 17 */ 18 public class ResponseDemo02 extends HttpServlet { 19 20 public void doGet(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 downloadFileByOutputStream(response);//下载文件,通过OutputStream流 23 } 24 25 /** 26 * 下载文件,通过OutputStream流 27 * @param response 28 * @throws FileNotFoundException 29 * @throws IOException 30 */ 31 private void downloadFileByOutputStream(HttpServletResponse response) 32 throws FileNotFoundException, IOException { 33 //1.获取要下载的文件的绝对路径 34 String realPath = this.getServletContext().getRealPath("/download/1.JPG"); 35 //2.获取要下载的文件名 36 String fileName = realPath.substring(realPath.lastIndexOf("\\")+1); 37 //3.设置content-disposition响应头控制浏览器以下载的形式打开文件 38 response.setHeader("content-disposition", "attachment;filename="+fileName); 39 //4.获取要下载的文件输入流 40 InputStream in = new FileInputStream(realPath); 41 int len = 0; 42 //5.创建数据缓冲区 43 byte[] buffer = new byte[1024]; 44 //6.通过response对象获取OutputStream流 45 OutputStream out = response.getOutputStream(); 46 //7.将FileInputStream流写入到buffer缓冲区 47 while ((len = in.read(buffer)) > 0) { 48 //8.使用OutputStream将缓冲区的数据输出到客户端浏览器 49 out.write(buffer,0,len); 50 } 51 in.close(); 52 } 53 54 public void doPost(HttpServletRequest request, HttpServletResponse response) 55 throws ServletException, IOException { 56 doGet(request, response); 57 } 58 }
文件下载注意事项:编写文件下载功能时推荐使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。
生成随机图片用作验证码:
生成图片主要用到了一个BufferedImage类。
20 response.setHeader("refresh", "5");//设置refresh响应头控制浏览器每隔5秒钟刷新一次 21 //1.在内存中创建一张图片 22 BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); 23 //2.得到图片 24 //Graphics g = image.getGraphics(); 25 Graphics2D g = (Graphics2D)image.getGraphics(); 26 g.setColor(Color.WHITE);//设置图片的背景色 27 g.fillRect(0, 0, 80, 20);//填充背景色 28 //3.向图片上写数据 29 g.setColor(Color.BLUE);//设置图片上字体的颜色 30 g.setFont(new Font(null, Font.BOLD, 20)); 31 g.drawString(makeNum(), 0, 20); 32 //4.设置响应头控制浏览器浏览器以图片的方式打开 33 response.setContentType("image/jpeg");//等同于response.setHeader("Content-Type", "image/jpeg"); 34 //5.设置响应头控制浏览器不缓存图片数据 35 response.setDateHeader("expries", -1); 36 response.setHeader("Cache-Control", "no-cache"); 37 response.setHeader("Pragma", "no-cache"); 38 //6.将图片写给浏览器 39 ImageIO.write(image, "jpg", response.getOutputStream()); 40 } 41 42 /** 43 * 生成随机数字 44 * @return 45 */ 46 private String makeNum(){ 47 Random random = new Random(); 48 String num = random.nextInt(9999999)+""; 49 StringBuffer sb = new StringBuffer(); 50 for (int i = 0; i < 7-num.length(); i++) { 51 sb.append("0"); 52 } 53 num = sb.toString()+num; 54 return num; 55 } 56 57 public void doPost(HttpServletRequest request, HttpServletResponse response) 58 throws ServletException, IOException { 59 doGet(request, response); 60 }
1 response.setDateHeader("expries", -1); 2 response.setHeader("Cache-Control", "no-cache"); 3 response.setHeader("Pragma", "no-cache");
1 response.setHeader("refresh", "5");//设置refresh响应头控制浏览器每隔5秒钟刷新一次
请求重定向指:一个web资源收到客户端请求后,通知客户端去访问另外一个web资源,这称之为请求重定向。
应用场景:用户登陆,用户首先访问登录页面,登录成功后,就会跳转到某个页面,这个过程就是一个请求重定向的过程
实现方式:response.sendRedirect(String location),即调用response对象的sendRedirect方法实现请求重定向
sendRedirect内部的实现原理:使用response设置302状态码和设置location响应头实现重定向
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
请求转发:指一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理。
请求转发的应用场景:MVC设计模式。
在Servlet中实现请求转发的两种方式:
1、通过ServletContext的getRequestDispatcher(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
1 RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp"); 2 reqDispatcher.forward(request, response);
2、通过request对象提供的getRequestDispatche(String
path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
request.getRequestDispatcher("/test.jsp").forward(request, response);
一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发/307。
一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源进行处理,称之为请求重定向/302。
Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。
在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法。
如果在元素中配置了一个
<load-on-startup>
元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
在JavaWeb开发中,只要是写URL地址,那么建议最好以”/”开头,也就是使用绝对路径的方式,那么这个”/”到底代表什么呢?可以用如下的方式来记忆”/”:如果”/”是给服务器用的,则代表当前的web工程,如果”/”是给浏览器用的,则代表webapps目录。