Day16-response

昨日重点提点:

1)javaEE经典三层架构:
servlet:控制服务流程
service:服务业务
dao:dao操作数据库

2)我们写的所有的servlet都会编译到web-inf文件夹下面的classes去(或者是工程下面的build文件夹下的classes中去)
web-inf文件夹下面的文件原则上不可访问,是受保护的(但还是有方法可以访问的,但是只允许服务器内部进行访问)

这里写图片描述
斜线其实就代表的是webContent文件夹下的文件
路径问题:
ServletContext.getRealPath(路径):路径写法从webContent文件夹下面开始写。
ServletContext.getResource(路径):路径写法也是从webContent文件夹下面开始写。
这里写图片描述
这里写图片描述


response

本质上是:HttpServletResponse接口对象
response操作的三大部分:
操作响应行;
操作响应头;
操作响应体;


(一)操作响应行:
常见api:
response.setStatus(int status)
针对没有问题的情况,1XX,2XX,3XX
response.setError(int Status)
response.setError(int Status,String 描述);
针对4XX,5XX
状态码单纯设置是没有太大意义的,要结合响应头设置一起使用。
这里写图片描述


(二)操作响应头:
格式:key:value(可能有多个)

重要的api
response.setHeader(key , value) //如果这个key有值,会被覆盖,重新设置一个值。
了解的api
response.setIntHeader(key ,value)
response.setDateHeader(key ,value )
response.addHeader(Key , value) //添加一个key的多个value值的时候使用
response.addIntHeader(key ,value )
response.addDataHeader(key ,value )

常见的响应头:
content-type:响应的内容的类型
text/html;charset=utf-8;
location:重定向的时候,需要节后302状态码使用
refresh:告诉浏览器刷新去哪里
秒数;url=连接的地址
content-disposition:告诉客户端如何处理内容
attachment;filename=文件名(附件下载)


重定向
//重定向的两种方法
//重定向

response.setStatus(302);
response.setHeader("location", "/Day15_0622_03MyLoginDemo/successLogin");
response.sendRedirect("路径")    重定向的简便操作!
response.sendRedirect("/Day15_0622_03MyLoginDemo/successLogin" )

//刷新到别的页面

respoonse.getWriter().println("页面3秒后跳转")
response.setHeader("refresh","1;url=/Day16_response/dajiang.html")

和重定向的区别,状态码不会出现302,正常情况下应该全部是200的状态码
1)状态码不一样,重定向的状态码是302,使用刷新方法的状态码是200;
2)设置的response响应体的内容不同;
重定向是设置状态码setStatus结合响应头中的location设置的自动跳转;
刷新方法使用的仅仅是响应头中的refresh,设置了跳转秒数和跳转url
3)重定向方法用户不易察觉,两次请求间隔时间很短;刷新方法可以指定跳转间隔时间;
其实重定向方法和刷新方法总的来说都是发送了两次请求。
刷新的另一种方式:(常用)
在html头中写meta标签

<meta http-equiv="refresh" content="3;url=地址">

//中文编码问题
response.setContentType(“text/html;charset=utf-8”)
setContentType方法里面其实有两步
分别设置了编码规则和浏览器的解码规则。
这里写图片描述


(三)操作响应体:向页面上输出的内容

PrinterWriter:输出字符(常用)
ServletOutputStream:输出字节
(输出的内容如果不是文本就用这个)

1)PrinterWriter

Printer writer = response.getWriter();
          //返回值就是PrinterWriter
writer.println("hello print writer");

//向页面输出一个复杂内容,比如表格
writer.println("<table border='1px'>");
writer.println("<tr>");
writer.println("<td>");
     writer.println("username");
writer.println("</td>");
writer.println("</tr>");
writer.println("</table>");
//以后可以通过jsp来写,jsp本质上也是一个servlet
//Java server page

2)ServletOutputStream
用于输出二进制的数据内容的时候使用
不能够和PrintWriter同时使用,会illegal,报500异常
ServletOutputStream os = response.getOutputStream();
os.print(“hello outputStream”); //纠正,以后不要写成把print写成了write了
//这种方法是二进制的写法,不能够直接输出中文
//可以看看PrintWriter的print方法的源码,只要不是规定的编码格式iso_8859_1就报异常

//这种方式要这样输出中文
response.setContentType(“text/html;charset=utf-8”);
os.write(“张三”.getBytes(“utf-8”)); //这里就要写成write,因为转换成了二进制数据输出了
//这种写法方式绕过了print底层源码的只要不是is0_8859_1编码就报错的方式。直接改为二进制输出了。

PrintWriter和ServletOutputStream:
1)两个流不能够同时使用,报500异常。互斥;

!关于换行问题:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType(“text/html;charset=utf-8”);

       javax.servlet.ServletOutputStream os = response.getOutputStream();
       os.println("outputStream success!");
       os.println("outputStream success!");
       os.println();
       os.write("哈哈哈".getBytes("utf-8"));

}
执行结果:
上述代码是表示用html格式打开文件,需要换行的时候需要手动加上一个br标签
(加了Contenttype里面有一个话,text/html,告诉程序以html格式打开文件,而html中擅自加换行是没有用的,没有显示效果,需要加标签)
这里写图片描述


重要案例: 下载文件

下载方式一: 超链接下载方式
浏览器智能后的后果,浏览器能够直接解析,就会直接显示。不会下载了。要下载就要目标另存为
经测试,txt文件和img文件是可以直接在浏览器中打开的;
doc文件和zip等文件链接之后是需要下载的。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
      <div>
           <a href="/Day16_0623_02DownloadDemo/Files/file1.doc">file1</a><br/>
           <a href="/Day16_0623_02DownloadDemo/Files/img1.jpg">img1</a><br/>
           <a href="/Day16_0623_02DownloadDemo/Files/txt1.txt">txt1</a><br/>
      </div>
</body>
</html>

下载方式二:用编码方式下载文件:
download为一个servlet程序,后面接的?表示默认的get请求,后面接提交参数
编码方式:涉及到两个头一个流
1)流:servletOutputStream
2)content-type:指定文件类型
3)content-disposition:内容的处理方式
步骤:
获取要下载的文件的名称
设置content-type
设置content-disposition
输出流,从文件输入流中获取数据

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //获取要下载的文件的名称
           String name = request.getParameter("name");
           ServletContext servletContext = this.getServletContext();
           //编码下载方式需要设置两个头一个流
           String mimeType = servletContext.getMimeType(name);
           //设置一个头:ContentType
           response.setContentType(mimeType);
           //设置一个头:Content-disposition
           response.setHeader("content-disposition", "attachment;filename="+name);
           //一个流:getOutputStream
           //获得输出流
           ServletOutputStream os = response.getOutputStream();
           //从文件的输入流中获取数据
           InputStream is = servletContext.getResourceAsStream("/Files/"+name);
           //拷贝
           byte[] bytes = new byte[8192];
           int len=0;
           while((len = is.read(bytes))!=-1){
                 os.write(bytes, 0, len);
           }
           //关闭流,os流是不用关闭的,服务器会自动调用完成后关闭。
           is.close();
      }

这个案例的问题:
所有的文件名字都是数字和中文

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

           //两个流一个头
           ServletContext servletContext = request.getServletContext();
           //获取文件名
           String name = request.getParameter("name");
           System.out.println(name);
           //获取文件的mime类型
           String mimeType = servletContext.getMimeType(name);

           //演示一下为了避免中文乱码的问题:
           String encode = URLEncoder.encode("下载.jpg", "utf-8");

           //设置头:contentType
           response.setContentType(mimeType);
           //设置头:content-disposition
           response.setHeader("content-disposition", "attachment;filename="+encode);
           //输入流
           InputStream is = servletContext.getResourceAsStream("/Files/"+name);
           //输出流
           ServletOutputStream os = response.getOutputStream();
           //拷贝文件
           byte[] bytes = new byte[8192];
           int len = 0;
           while((len=is.read(bytes))!=-1){
                 os.write(bytes,0,len);
           }
           is.close();
      }

//案例说明:
这个案例用URLEncoder.encode()修改的,只是下载后显示的文件的名字,如上例,下载后显示的文件名称会变成“下载.jpg”;但是连接中的文件名字和取web项目中查找的name都是没有改变的。
这种将中文转化成为utf-8的编码方式的形式适用于chrome、ie等浏览器,但是不包括火狐浏览器,因为火狐采用的不是utf-8的编码方式

利用工具类,根据响应的浏览器选择响应的编码方式处理中文乱码问题

public class Img1 extends HttpServlet {
      private static final long serialVersionUID = 1L;

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

           //两个流一个头
           ServletContext servletContext = request.getServletContext();
           //获取文件名
           String name = request.getParameter("name");
           System.out.println(name);
           //获取文件的mime类型
           String mimeType = servletContext.getMimeType(name);

           //演示一下为了避免中文乱码的问题:
//         String encode = URLEncoder.encode("下载.jpg", "utf-8");
           //获得request中的请求头中的user-agent
           String agent = request.getHeader("user-agent");
           //利用工具类,根据不同的浏览器对含有中文的文件名进行编码
           String name2 = DownLoadUtils.getName(agent, "测试.jpg");

           //设置头:contentType
           response.setContentType(mimeType);
           //设置头:content-disposition
           response.setHeader("content-disposition", "attachment;filename="+name2);
           //输入流
           InputStream is = servletContext.getResourceAsStream("/Files/"+name);
           //输出流
           ServletOutputStream os = response.getOutputStream();
           //拷贝文件
           byte[] bytes = new byte[8192];
           int len = 0;
           while((len=is.read(bytes))!=-1){
                 os.write(bytes,0,len);
           }
           is.close();
      }

案例:点击切换验证码
作用:防止暴力攻击
方式一:(low的方式)
利用给的servlet文件CodeServlet.java

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>点击切换验证码</title>
  <script>
  function changeCode(){
  document.getElementById("img1").src="/Day16_0624_01ChangeCodeDemo/code?i="+Math.random();
  }
  </script>

</head>
<body>
  <div>
  验证码<img id="img1" src="/Day16_0624_01ChangeCodeDemo/code" onclick="changeCode()" />
  </div>
</body>
</html>

方式二:
使用第三方的jar包
有两个包:commons-io-1.4.jar ValidateCode.jar

public class Code2 extends HttpServlet {
      private static final long serialVersionUID = 1L;

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           ValidateCode validateCode = new ValidateCode(300, 120, 4, 1500);
           //获得随机生成的code,后期校验使用
           String code = validateCode.getCode();
           //输出生成的验证码图片
           validateCode.write(response.getOutputStream());
      }

内省技术:Introspector

内省(Introspector)是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。
一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

面试:请说一下内省和反射的区别:
1)内省底层还是使用的反射技术, 只是做了一层封装, 主要是用来操作标准javabean, (标准javabean里面有get/set方法 );操作的范围比反射要小。
2)内省里面一个重要的东西是:PropertyDescriptor 属性描述器
3)简单来说:内省主要是操作javabean属性,get/set方法
反射: 可以操作类里面所有的字段,属性,方法,构造
两者都是通过字节码文件实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值