天天看点

04Servlet-5. Servlet的类试图详解*

1、Servlet的参数配置

1.Servlet的参数可以在web.xml中通过init-param元素来配置

2.参数的读取需要借助ServletConfig对象(该对象由容器创建)

   3.每一个Servlet都有对应的ServletConfig对象,彼此间不共享

  2、可能出现的线程安全问题
   由于Servlet对象在内存中有一个,所有定义Servlet的实例变量,在用户访问时会有线程竞争问题。

   解决办法:

   1.同步处理。(不建议使用)

   2.搞出多个Servlet实例。(不建议使用)

   SingleThreadModel接口:如果某个Servlet实现了该接口,容器有可能会采用1或2的方式来应对。(不同服务器实现不同)

   Tomcat是采取了2方案。废弃的接口     

   3、原则:尽量把变量定义为局部变量。对于没法定义为局部变量的变量,应做同步处理,但同步代码块应尽可能的小。

  3、ServletConfig
   使用ServletConfig可以获取WEB-INF 配置文件init-param里面的值(非全局,只能获取当前Servlet里面的配置数据);

 1.获取指定参数名字的值

//注意:init-param只能放在servlet-class配置标签后面

   String value = getServletConfig().getInitParameter("ppp"); 

2.获取所有参数名字

   //获取顺序:按自然排序获取名字

    Enumeration names=   getServletConfig()

    .getInitParameterNames();

   while(names.hasMoreElements()){

       String name =(String) names.nextElement();

   }



  4、ServletContext
   1、ServletContext概念

       应用活多长,ServletContext对象就活多长(生命周期)

       容器在加载应用时就会创建ServletContext对象,它代表当前JavaWeb应用(全局)。

       本身是一个域对象:该对象内部维护了一个Map<String,Object>(域对象)

                 访问域对象数据的方法:

                 ObjectgetAttribute(String name):通过名称获取对象。

                 voidsetAttribute(String name,Object obj):忘Map中塞一个对象。name在                           Map中不存在是添加,存在是替换

                 voidremove(String name)

                 getAttributeNames():获取Map中的所有key值

   2、作用

          1、实现各个Servlet间的数据共享。(数据共享)

          2、获取应用的全局参数配置(参数配置)

                 在web.xml里面配置

                        <context-param>

                               <param-name>encoding</param-name>

                               <param-value>UTF-8</param-value>

                        </context-param>

       3、 从web-xml配置文件中获得值的方法:

   //这个getServletContext方法在GenericServlet类中

   String value = getServletContext().getInitParameter("name");

  5、三种读取配置文件的方式
          1、ServletContext的getRealPath(Stringpath):根据path获取绝对路径。path必须以/         开始,相对于当前应用的绝对路径

                 特点:用户JavaWeb环境下,JavaWeb环境下可以读取到当前应用中的任何资        源。

          2、ResourceBundle:构造实例时,传入基名。(国际化的类)

                 特点:可以用在非web环境下,只能读取properties的资源文件;只能加载类         路径下的资源文件;

          3、ClassLoader:

                 特点:可以用在非web环境下,只能加载类路径下的资源文件;读取类路径                 下的所有资源文件。      

具体实例代码:

1.ServletContext读取类路径下的property资源文件

Stringpath = getServletContext().getRealPath

     ("/WEB-INF/classes/com/itheima/servlet/db11.properties");

   Properties pro = new Properties();

   pro.load(new FileInputStream(path));

   String value = pro.getProperty("url");      

2.用ResourceBundle读取资源文件

//注意ResourceBundel的路径,没有/,没有后缀名,因为他知道是Properties文件,

//并且把Properties当成类的读取方式来读取(如果有包,包名用.分隔),具体如下

   ResourceBundle rb = ResourceBundle.getBundle

    ("com.itheima.servlet.db11");

   String value = rb.getString("url");      

3.用类加载器的URL类读取资源文件

ClassLoader cl = MyServlet3.class.getClassLoader();

   //以相对路径的方法来读取文件

   //如果路径中有空格,tomcat就会把空格翻译为%20,就会出错,这就是为什么安装  

    //时为什么不能有空格路径

   URL url = cl.getResource

    ("com/itheima/servlet/db11.properties");

   //url的getPath方法获取的是绝对路径

   String path = url.getPath();

   Properties pro = new Properties();

   pro.load(new FileInputStream(path));

   String value = pro.getProperty("url");      

4.用类加载器的getResourceAsStream方法读取资源文件(获取资源的比较常用的方法)

ClassLoader cl = MyServlet3.class.getClassLoader();

   //调用ResourceAsStream(以流的形式拿出资源);

   InputStream fis = cl.getResourceAsStream

    ("com/itheima/servlet/db11.properties");

   Properties pro = new Properties();

   pro.load(fis);

    String value = pro.getProperty("url");      

6、HttpServletResponse

字节流输出中文数据的乱码问题

使用response.getOutputStream()获得字节流。

   sendRedirect是在httpServletResponse这个接口定义的,不是在ServletResponse定义的

   字节流以UTF-8编码输出中文数据getBytes("UTF-8"),而浏览器用默认编码(GBK)解码,这时就会有乱码      

解决:

1.浏览器选择“查看”菜单选择UTF-8,解决乱码问题。(不可取)

   2.指示浏览器查看码表.response.setHeader("Content-Type","text/html;charset=UTF-8");

   3.向客户端收到的html内容中增加标记:<metahttp-equiv="Content-Type"        content="text/html;charset=UTF-8">

   4.发送时用Reponse. setCharacterEncoding(“utf-8”)

   5、调用response.setContentType("text/html;charset=UTF-8"):告知客户端使用的编码      

Tips: GBK包含ascll码

7、Servlet的字符流输出

获取Servlet字符输出流方法response.getWriter():

Servlet的字符输出流输出时查的码表为iso-8859-1(Servlet规范指定的)

    字符流和字节流互斥。在同一个Servlet中,只能用其中的一个流。

     容器会自动关闭response开启的流。

   字符流乱码解决办法:

 两步:

          1.设置输出字符数据时查的码表:response.setCharacterEncoding(“utf-8”)

          2.通知客户端以什么码表进行解码。

     response.setHeader(“Content-type”,”text/html;charset=utf-8”)



          response.setContentType("text/html;charset=UTF-8")能提供上述两步功能(字符流)。

   所以使用字符流时调用setContentType()方法能轻松解决乱码问题      

8、HttpServletRequest

1.常用的方法

request.getRequestURL()//获取请求url地址:http://localhost:8080/day05/servlet/RequestDemo1

request.getRequestURI()//获取请求的资源地址:/day05/servlet/RequestDemo1

request.getQueryString()//get方式的数据:username=admin&password=123

request.getRemoteAddr()//客户端的IP地址

request.getRemoteHost()//客户端的主机名称

request.getRemotePort()//客户端的端口号 1024~65535之间的任意一个没有被占用的端口

request.getMethod()//请求方式:get或post

request.getContextPath()// 当前应用的名称 /day05

2.获取请求头的值

//获取所有的请求头名称和值

privatevoid test3(HttpServletRequest request, HttpServletResponse response)

                 throwsServletException, IOException {

          Enumeration enumers = request.getHeaderNames();

          while(enumers.hasMoreElements()){

                 StringheaderName = (String)enumers.nextElement();

                 System.out.println(headerName+"="+request.getHeader(headerName));

          }

   }      

//获取重名头的值

privatevoid test2(HttpServletRequest request, HttpServletResponse response)

                 throwsServletException, IOException {

          Enumerationenumers = request.getHeaders("Accept-Encoding");

          while(enumers.hasMoreElements()){

                 Stringvalue = (String)enumers.nextElement();

                 System.out.println(value);

          }

   }      

//获取单一的头

privatevoid test1(HttpServletRequest request, HttpServletResponse response)

                 throwsServletException, IOException {

          String value =request.getHeader("Accept-Encoding");

          System.out.println(value);

   }      

3.获取正文所有内容

//方法:请求的输入流

   OutputStream out = response.getOutputStream();

   InputStream is = request.getInputStream();

   int length = -1;

   byte[] by =new byte[1024];

   while((length=is.read(by))!=-1){

       out.write(by,0,length);

}      

4.封装javaBean

//将页面数据封装到JavaBean中:利用BeanUtils框架(需要jar包)



   User user = new User();

    //注意事项!这里的map的value值是String[]类型,因为同一个名字可以有多个值

   Map<String, String[]> map = request.getParameterMap();

   BeanUtils.populate(user, map);



//将页面数据封装到JavaBean中(第一种)

   User user = new User();

   //获得页面所有属性的名字

   Enumeration<String> names = request.getParameterNames();

   while(names.hasMoreElements()){

       String name =names.nextElement();

        String value =request.getParameter(name);

       //获得属性描述器,内省

       PropertyDescriptorpd =  new      

        PropertyDescriptor(name,User.class);

       Method method = pd.getWriteMethod();

       method.invoke(user, value);

   }

//将页面数据封装到JavaBean中(第二种)

   User user = new User();

   //获取页面所有属性的Map

   Map<String,String[]> map = request.getParameterMap();

    //注意事项!这里的map的value值是String[]类型,因为同一个名字可以有多个值

   for(Map.Entry<String, String[]> entry:map.entrySet()){

       String name = entry.getKey();

       String[] value = entry.getValue();

       PropertyDescriptor pd = new

         PropertyDescriptor(name,User.class);

       Method method = pd.getWriteMethod();

       method.invoke(user, value);



   }      
//获取图片绝对路径

   String path = getServletContext().getRealPath("/美女.jpg");

   //获取图片名绝对路径名称:G:xxx\xxx\美女.jpg

   String name = path.substring(path.lastIndexOf("\\")+1);

   FileInputStream fis = new FileInputStream(path);

    //如果显示图片,就需要设置Content-Type为application/octet-stream

   response.setHeader("Content-Type","application/octet-stream");



响应消息头要遵循html的规则,必须把不安全的东西重新编码(加密变成安全字符集里面      
下载文件是浏览器会自动帮你对安全字符集解码



   response.setHeader

   ("Content-Disposition","attachment;filename="

    +URLEncoder.encode(name),"utf-8"));

   int length = - 1;

   byte[] b =new byte[1024];

    while((length =fis.read(b))!=-1){

       response.getOutputStream().write(b,0,length);

     }

    }