小言_互联网的博客

Servlet学习(3)-Response和ServletContext

380人阅读  评论(0)



说明

  因为是个人复习java的总结,所以结构稍显杂乱,有些语句过于口语化.
  下面是部分的servlet内容,先提了一下BeanUtils,后面主要是Response对象和ServletContext,之后就开始cookie,session等内容


BeanUtils

  上一篇提到使用BeanUtils将request获取的map集合转换成User对象.这里再进一步了解一下这个工具类.
  其实这个工具类就是用来简化封装javaBean的.javaBean其实就是标准的java类,像之前提到的案例中的User就是.有空参的构造器,public修饰,成员变量为私有并写了getter和setter方法.

  这个工具类中有一个很特殊的概念,属性.也就是setter和getter方法名中标识修改的当前类的属性部分的名称的小写叫属性.其实就是setHehe()中hehe为属性名,而其中具体修改的成员变量可以是修改age的,这没有关系,但是一般写成统一的比较好.
属性就在这个工具类的方法中使用到了.

setProperty()

  通过传入对象和属性还有属性值来修改属性,注意这里是属性不是成员变量.也就是说如果你在setHehe()方法中修改age值,然后用这个方法传入age作为属性,那是没有用的.因为修改的不是成员变量.只有传入hehe作为参数才会对age进行修改.

getProperty()

  同理,就是获取属性中的值.但是实际使用中应该没人会自找麻烦,所以把属性当作成员变量来看也没什么问题.

populate(Object obj, Map map)

  可以将map的键值对数据封装到对象中.


网页的响应状态码

  也就是平常经常见到的404之类的,这个状态码都是三位的,总的分五类,一类的状态码表达的意思差不多
  1XX
  服务器在接收客户端消息但是没有接收完成,等待一段时间之后询问客户端的一个状态码,比较不常出现
  2XX
  标识响应成功,200成功
  3XX
  重定向,其实就是响应浏览器,让浏览器去访问其他资源的一个状态码.302重定向,304访问缓存资源.对于很多的js之类都是靠缓存的,重复访问时就返回这个.
  4XX
  客户端错误,404路径错误没有对应资源.405请求方式没有对应的do,也就是没写doGet,却用get请求
  5XX
  服务器端错误,500服务器内部出现异常


Response

  其实就是服务器对于浏览器发送请求消息的回复.具体的组成部分有下面几个部分,其实跟Request很像.

  响应行

HTTP:/1.1 200 OK

  协议和版本信息 状态码 状态码描述

  响应头

Content-Type: text/html; charset=utf-8

  服务器告诉客户端响应数据体的格式以及编码格式.

Content-disposition: in-line

  服务器告诉客户端使用什么方式来打开响应体,默认的时候时in-line,其实就是显示在当前页面.
  需要注意可以设置值为attachment;filename=XXX;也就是以附件的形式打开,换种说法就是下载时弹出来的下载提示.这个在设置下载内容的时候会使用到.

  响应空行
  没什么好说的,跟请求空行一样,只是用来分一下区域

  响应体
  就是根据请求返回的数据,访问页面的时候就会有很多,像图片,html,js之类的


Response设置响应消息

setStatus(int sc)

  设置响应状态码

setHeader(String name,String value)

  设置响应头

PrintWriter getWriter()
servletOutputStream getOutputStream()

  设置响应体,其实和请求头中的读取一样,需要获取流对象,然后再获取数据.


重定向和转发

  重定向是再客户端访问服务器之后,服务器返回重定向状态码并设置响应头,然后客户端就会根据响应去访问新的资源,然后获得正确响应.
  转发则是在服务器的内部,将其中的一个Servlet转发给另外一个Servlet,从而达到目的.


  从这个过程就可以明白,重定向会有两次请求.而转发是一次请求.重定向的地址栏发生了变化,而转发没有.重定向可以访问其他站点的资源而转发只能访问当前站点内部的资源.重定向不能使用request来共享数据,而转发可以共享这个数据.

  重定向的过程,也就是返回响应码并设置响应头这个过程其实被封装成了一个方法

sendRedirect("路径")

  就可以实现重定向,其实内部代码就是上面描述的两句,设置响应码,设置响应头


路径写法

  再复习一下,web中写的路径实在太多了,多巩固几遍总没错,这里主要基于web来讲

  相对路径是相对于当前目录下的资源定位,
  使用./开头表示相对路径,但是一般不写,除非需要返回上级目录使用…/


  绝对路径就是从项目部署的虚拟路径开始到目的资源的路径地址

/项目虚拟路径/访问的页面

  使用的时候需要判断是给服务器使用的路径还是客户端使用的路径,客户端的额路径一般为绝对路径也就是需要带项目虚拟路径,而服务器中的转发路径可以使用相对路径,不需要项目虚拟目录.

  之后使用jsp的时候一般会使用动态的方式来获取虚拟目录,也就是说使用getContextPath()方法获取当前访问的路径,再使用这个路径加上后面访问的路径,组成一个完整的路径,这样就可以再改变项目虚拟路径之后不改变其他路径.


字符输出流数据乱码问题

  在使用字符输出流的时候,肯定是要使用response的getWriter()方法获取PrintWriter对象,然后再调用write()方法来输出数据.如果想要解决中文乱码,那么肯定就像之前request一样设置流的编码格式,也就是使用setCharacterEncoding();但是这就有一个问题,这样设置我们就需要知道浏览器使用的编码格式,这明显不符合需求.

  所以可以使用上面提到过的content-type来告诉浏览器使用什么方式解析.也就是setHeader("content-type","text/html;charset=utf-8").这样设置请求头.并且使用这个语句之后也不用设置流的编码,会自动使用相应的编码.但是还是比较麻烦,所以下main还有一种简单的方式.

setContentType()

  也就是专门用来设置编码格式的方法.

  同样的如果使用字节流输出数据,流程和字符流一样,乱码解决方式也一样.但是一般不用来输出中文,基本上是传输照片之类的.


验证码案例

  其实就是做一个验证码,随机生成内容的那种,但是做的比较丑,而且其实也没什么用,这种级别给图像识别一下秒破.只是练习一下响应.

//设置长宽
int width=100;
int height=50;
//创建一个image
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);

//创建图片的画笔
Graphics graphics = image.getGraphics();
//画底色
graphics.setColor(Color.PINK);
graphics.fillRect(0,0,width,height);
//画边框
graphics.setColor(Color.BLUE);
graphics.drawRect(0,0,width-1,height-1);

//随机显示的内容
String string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

Random random = new Random();
//随机绘画图像内容
for (int i = 0; i <= 4; i++) {
	int num = random.nextInt(string.length());
	char ch = string.charAt(num);
	graphics.drawString(""+ch,width/5*i-i*3,height/5*i+i*2);
}

//随机添加干扰线
graphics.setColor(Color.CYAN);
for (int i = 0; i < 11; i++) {
	int a = random.nextInt(width);
	int b = random.nextInt(width);
	
	int c = random.nextInt(height);
	int d = random.nextInt(height);
	graphics.drawLine(a,b,c,d);
}
//输出图像
ImageIO.write(image,"jpg",response.getOutputStream());
<script>
  window.onload = function () {
    var image = document.getElementById("image");
    var change = document.getElementById("change");
    image.onclick = function () {
      var date = new Date().getTime();
      image.src="/picture?"+date;
    }
    change.onclick = function () {
      var date = new Date();
      image.src="/picture?"+date;
    }
  }
</script>



ServletContext对象

  其实就相当于是部署在Tomcat上的整个应用,可以和Tomcat或者说服务器之间进行一些通信.
  主要的功能就是获取MIME类型,并且是一个域对象,获取文件的真实路径.
  使用ServletContext之前肯定要获取这个对象:

getServletContext()

  主要就是使用这个方法来获取对象,但是其实可以使用request对象获取或者使用HttpServlet中的这个方法获取,也就是this.来获取.两者获取到的ServletContext对象是一样的.很好理解,两个相当于都是获取整个web.


获取MIME类型

  MIME其实就是在互联网通信中定义的一种文件数据类型.其实就是text/html这个格式.

String getMimeType(String file)

  可以使用ServletContext对象调用该方法来获取MIME类型


域对象

  域对象的基本获取修改移除方法就不写了,和前面提到的request域对象是一样的.
  ServletContext的域范围,其实从其概念可以大概的明白,范围是整个web项目,也就是说服务器启动之后会创建这个对象,然后这个对象中的数据可以共享给所有访问的用户,所以使用的时候比较谨慎,如果存的数据太多会对内存造成压力,而且所有用户都能读取就不太安全.


获取文件的真实(服务器)路径

  其实就是获取文件在服务器中的路径,而不是相对于客户端的虚拟路径.比如说创建web在D盘下的某个文件夹,那么获取的真实路径其实就是从D盘开始的路径.这就是服务器下的真实路径,那么服务器端就能很好的去找到文件并加载.

String getRealPath("路径")

  使用上就是使用通过ServletContext对象来调用方法,然后获取路径.这里需要注意方法中传递的路径,其实是web中的路径.

  如果放在web下就是/需要的文件
  如果放在WEB-INF下就是/WEB-INF/需要的文件
  如果是在src中,其实会解码成classes文件夹放在WEB-INF下,所以就是/WEB-INF/classes/需要的文件.
  其实src下也可以通过classLoader获取,但是那就不能获取web下的文件,局限性比较大.


下载链接的案例

  如果单纯在超链接上连上需要提供给用户的资源,那么在浏览器中,如果可以解析就会自动被解析,显示到页面上.只有不能被解析的才能提示下载.那么需求是希望所有的文件都会下载,不会解析.


  那么分析,首先就需要一个Servlet类,并且将页面上的资源指向Servlet,同时需要在请求头后面带上需要下载的文件名.
  然后在Servlet类中就可以通过request获取这个文件名,再使用ServletContext对象获取真实路径.获取真实路径之后就可以使用字节流加载文件,并创建输出流.
  既然要输出了,就考虑设置响应头.那么就需要设置上面提到的conent-type,标记传输的文件的MIME类型,那肯定不能手动写MIME类型,就可以通过ServletContext获取文件的MIME类型.
  除此之外还需要设置响应为弹出下载,也就是content-disposition设置为attachment;filename=XXX
  那这样响应头就设置好了,就可以创建缓冲区将字节输入流读取,并输出到字节输出流.最后释放一下输入流资源.输出流随request一起消失就没必要释放了.


具体实现如下:

//获取头文件传来的文件名,也就是前面具体是什么连接需要下载
String filename = request.getParameter("filename");

//通过ServletContext获取真实路径
ServletContext servletContext = request.getServletContext();
String realPath = servletContext.getRealPath("/text/" + filename);

//创建文件的字节输入流
FileInputStream fileInputStream = new FileInputStream(realPath);

//创建字节输出流
ServletOutputStream outputStream = response.getOutputStream();

//通过Servlet获取文件的MIME格式并设置响应头格式
String mimeType = servletContext.getMimeType(realPath);
response.setHeader("content-type",mimeType);

//设置响应的方式和路径
response.setHeader("content-disposition","attachment;filename="+filename);

//缓冲区
byte[] buff = new byte[1024];
int len = 0;
//读取文件并输出
while ((len=fileInputStream.read(buff))!=-1){
   outputStream.write(buff,0,len);
}
fileInputStream.close();

  但是实际上,其中还有一些问题,需要继续思考.如果文件名为中文,那肯定会出现编码的问题.如果想要自己解决那就得用以下的步骤去解决.
  首先就需要使用request对象获取浏览器的信息,也就是user-agent
  然后根据这个信息中包含的不同的浏览器信息,使用不同的编码方式编译这个文件名,然后再将编译后的文件名放进响应里传输.

  但是这样做起来就麻烦了点,具体浏览器的编码方式都得去查.所以还是用前人做好的,这种工具类很多.



如有错误欢迎读者批评指正!!


转载:https://blog.csdn.net/weixin_43913376/article/details/106304786
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场