Servlet详解一(配置及request和response)

一、线程安全问题:

当多个客户端并发访问一个Servlet时,Web服务器会为每一个客户端请求创建一个线程,并在线程上调用servletservice方法,而当service方法访问共享数据时,就存在线程安全问题了。

在早期的处理此线程安全问题的一种思路是让Servlet实现SingleThreadModel接口,此接口是一个标识接口,各web服务器对此的解释不同,一般分为每个请求创建一个实例对象与调用service方法同步。Tomcat是采取了方式一为每个请求都创建一个实例。但这两种方式都不合适,因为servlet2.4规范中已将SingleThreadModel接口过时了。而真正的处理此线程安全的合理方式时,应该尽量避免使用共享数据,尽量定义局部变量。

二、Servlet可配置参数及读取参数信息

1.web.xml中,需要配置<servlet><servlet-mapping>标签,还可以在<servlet>标签下面定义子元素<init-param>,在此子元素下面配置<param-name><param-value>子元素。而读取<servlet>子元素<init-param>中配置的信息,可以用ServletConfig对象的getInitParameter方法。因为ServletConfig对象是,Web容器在创建Servlet后,调用servletinit方法时传进去的,所以各种servletServletConfig对象各不一样。同一servlet中可以配置多个init-param元素,同一param-name为被后面的覆盖。

举例如下:

<servlet>

<servlet-name>ServletConfigD1</servlet-name>

<servlet-class>com.itheima.servlet.ServletConfigD1</servlet-class>

<init-param>

<param-name>url</param-name>

<param-value>jdbc:mysql</param-value>

</init-param>

<init-param>

<param-name>url</param-name><!-- 允许有重复的,有重复的时最终读取的最后一个url -->

<param-value>jdbc:oracle</param-value>

</init-param>

<init-param>

<param-name>username</param-name>

<param-value>scott</param-value>

</init-param>

<init-param>

</servlet>

而具体读取代码示例:getServletConfig().getInitParameter(“url”)

2.servlet中另一种方式读取配置信息,就是将param配置在整个应用级中,为所有servlet共享,则定义在servlet元素的外面,与servlet元素同一层级。而读取应用级的读取信息,要用到应用级的对象ServletContext对象,ServletContext对象一个应用只有一个对象,在应用被web服务器加载时被加载初始化创建对象,而在应用被web服务器停用或卸载时消亡。是随着整个应用的加载而加载,随着整个应用的消亡而消亡的。具体举例如下:

<context-param>

<param-name>encoding</param-name><!--注意context-param中不允许有重复的param -->

<param-value>utf-8</param-value>

</context-param>

读取配置信息encoding,只需要在servlet中使用getServletContext().getInitParameter(“encoding”)即可。

三、三种读取配置文件的方式,另详细。见三种读取文件方式。

四、HttpServletResponse对象详解

1.输出中文内容

response对象中,输出流可以有response.getOutputStream的字节流输出与response.getWriter字符流输出。而对中文的输出,若没有进行输出的编码说明时,直接输出中文,OutputStream没有乱码问题,而Writer会有乱码问题。

原因:response.getOutputStream采用的是默认的编码GBK,而response.getWriter采用的是ISO-8859-1编码的。而客户端浏览器也采用默认的编码GBK,所以字节流没有问题,而字符流出现了乱码。

解决向:客户端输出中文乱码文件,

对于字节流OutputStream来说:可以用合适的str.getBytes(“utf-8”)编码后输出。但输出前要告诉浏览器用了什么编码了,这个信息一般放在响应头中,如response.setHeader(“content-type”,”text/htm;charset=utf-8”),当然也可以用response.setContentType(”text/htm;charset=utf-8”),或者write("<meta http-equiv='Content-Type'content='text/html; charset=utf-8' />".getBytes());

对于字符流Writer来说,可以直接用response.setContentType(”text/htm;charset=utf-8”)来搞定即可,它相当于

response.setCharacterEncoding(“UTF-8”);response.setHeader(“content-type”,”text/htm;charset=utf-8”);两句。

2.中文文件名下载乱码问题:

在下载前的response.setHeader(“content-disposition”,”attachment;filename=strNam”);需要注意,不能直接将strName输出,要用URLEncoder进行encode(strNam,”utf-8”)进行编码后,再输入。因为这种中文名下载会像在百度输入关键字,采用get请求输入中文参数一样,会经过httpURL编码的。

3.控制浏览器缓存一页面时间为1小时(不常变的页面,为了减轻服务器的压力,而设置缓存时间长点)

response.setDateHeader(“Expires”, System.currentTimeMillis()+1000*60*60);

4.生成随机图片思路:

就是用BuffedImage,得到Graphics画笔后,先设置color后,画个边框drawRet..,再设置另一clor接着在框中填充前景fillRet…,接着画些干扰线如drawLine,接着生成随便几个数字用drawString画出来,最后将画在内容中的数据,输出在response.getOutputStream中,用ImageIO.write即可了。

5.请求重定向

前遍http入门中讲到在响应状态码中包括302307状态码即是请求重定向了。它是http请求一组件时,此组件告诉浏览器不要向它请求,告诉了另一个地址,让浏览器重写向新的资源地址请求。所以这个过程发生了两个http请求。则表现在url地址会变化,且是两次http请求增加了服务器的负担。

代码示例:

Response.setState(302) response.setHeader(“Location”,”/demo5/servlet/SD1.do”)也可以用一句搞定response.sendRedirect(”/demo5/servlet/SD1.do”)

6.Response输出流的一些细节:

6.1servlet中不能同时使用getOutputStreamgetWriter方法,两者是互斥着。

6.2servlet中输出的内容只是缓存进了response的输出流中,而Web容器会根据输出流缓存内容进行组织下加些响应头输出来。

6.3Web容器会在调用servletservice方法后,检查response的输出流是否已经关闭了,若没有关闭则web容器会关闭输出流。

五、HttpServletRequest详细:

1.常用的一些获取客户端信息方法:

a)getRequestURL方法返回客户端发出请求时的完整URLhttp://.../ServletReLine

b)getRequestURI方法返回请求行中的资源名部分。如/servlet/ServletRequestLine

c)getQueryString方法返回请求行中的参数部分。

d)getRemoteAddr方法返回发出请求的客户机的IP地址

e)getRemoteHost方法返回发出请求的客户机的完整主机名

f)getRemotePort方法返回客户机所使用的网络端口号

g)getLocalAddr方法返回WEB服务器的IP地址。

h)getLocalName方法返回WEB服务器的主机名

i)getMethod得到客户机请求方式 GET或者POST

j)getContextPath方法返回应用上下文地址: /demo5

2.获取请求头信息

a)getHead(name)方法返回指定name的值的头信息

b)getHeaders(String name)方法返回同一name多个值的头信息,指Warning头信息。

c)getHeaderNames方法所以头的name信息

3.获取客户端请求参数(客户端提交的值)

a)getParameter(name)方法用在一个name一个值

b)getParameterValuesString name)方法用在一个name多个值

c)getParameterNames方法将所有请求参数名返回

d)getParameterMap方法 //做框架用,非常实用,包含请求参数名与值

注意这里有个BeanUtils.populate(Obj,request. getParameterMap)可设值到obj.

e)getInputStream

4.解决请求参数乱码问题:

GET方式的乱码:

<a href=”/demo5/servlet/RD2?name=中国”>CN</a>,直接用request.getParameter得到的字符串strCN将会乱码,这也是因为GET方式是用httpurl传过来的默认用iso-8859-1编码的,所以首先得到的strCn要再用iso-8859-1编码得到原文后,再进行用utf-8(看具体页面的charset是什么utf-8gbk)进行解码即可。new String(strCn.getBytes(“ISO-8859-1”),“UTF-8”);

POST方式的乱码:只需要request.setCharacterEncoding("UTF-8"):即可。

5.表单数据的获取:

Checkboxinputselect等等,因checkbox一般是复选代表一组通常name属性是一值的,有多个值。所以要用request.getParameterValues(name)

6.request域对象与请求转发

request也是一域对象,可以用request.setAttribute(“name”,”value”)。在用在请求转发时,在另一servlet中,可以用request.getAttribute(“name”)得到值。当然不能用在response.sendRedirect(这个是请求重定向两个http请求,两个不同的request)而请求转发是指请求一组件时,此组件将请求request对象与去掉响应体的response对象原样传到另一servlet组件中,由另一servlet组件来处理请求。所以此时表现在:是一个http请求,URL地址没有变化。同一request对象,源response对象去掉响应体传到目标servlet中。

具体代码如下:

RequestDispatcher rd = request.getRequestDispatcher(path);

rd.forward(request,response);//forward前,窗口将把response中的响应体去掉,因为在源组件servletout.write的任何内容将丢失了。注意在源组件servlet中不能flush输出流或关闭输出流。

7.得到RequestDispatcher的方式,有以下两种:

7.1 Request.getRequestDispatcher(path)可用绝对路径/开关也可用相对路径,建议用绝对路径来搞定。

7.2 getServletContext().getRequestDispatcher(path)path只能是以/开头

8.包含

可以在一组件servlet中用请求分派器RequestDispatcherinclude方法,将目标组件servlet中的响应结果包含进源组件中,两种响应体输出结果一起输出出来。注意:目标组件中的servlet响应头将会被丢失:

具体代码如下:

RequestDispatcher rd = request.getRequestDispatcher(path);

rd.include(request,response);//目标中的响应头将会丢失。

9.各种相对路径与绝对路径的写法

若路径地址是给服务器用的,则不需要加应用名。直接以/开头代表应用路径/servlet…

若路径地址是给客户端用的,则需要加应用名。要用/demo5/servlet…

具体应用场景:

9.1 请求转发与包含是服务器行为可以用Request.getRequestDispatcher(“/servlet/SD2.do”)

9.2 请求重定向,用可以reqeust.sendRedirect(“/demo5/servlet/SD2.do”)

<ahref/> 客户端用的/demo5

<scriptsrc=""/> 客户端用的/demo5

<imgsrc=""/> 客户端用的/demo5

<linktype="text/css" href=""/>客户端用的/demo5

<formaction=""/>客户端用的/demo5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值