Java Web开发总结(一)

1、如何解决 tomcat 中文乱码问题?

2、如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet

 <!-- 将ServletDemo2配置成缺省Servlet -->
  <servlet-mapping>
    <servlet-name>ServletDemo2</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

 3、Servlet 线程安全:当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。

    3.1通过ServletContext获取web资源的绝对路径

    String path = this.getServletContext().getRealPath("/WEB-INF/classes/db/config/db3.properties");

4、ServletContext对象

       WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用
  ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
  由于同一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象


ServletContext context = this.getServletConfig().getServletContext();//获得ServletContext对象
context.setAttribute("data", data);  //将data存储到ServletContext对象
在另一个 servlet 中:

String data = (String) context.getAttribute("data");//从ServletContext对象中取出数据

5、获取WEB应用的初始化参数

在web.xml文件中使用<context-param>标签配置WEB应用的初始化参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <display-name></display-name>
    <!-- 配置WEB应用的初始化参数 -->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/test</param-value>
    </context-param>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

 

servlet 中 获取Web应用的初始化参数:


ServletContext context = this.getServletContext();
//获取整个web站点的初始化参数
String contextInitParam = context.getInitParameter("url");

6、页面跳转  用servletContext实现请求转发

(6.1)Request对象实现请求转发

        A、通过 ServletContext 的 getRequestDispatcher(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。 


ServletContext context = this.getServletContext();//获取ServletContext对象
RequestDispatcher rd = context.getRequestDispatcher("/servlet/ServletContextDemo5");//获取请求转发对象(RequestDispatcher)
rd.forward(request, response);//调用forward方法实现请求转发
 
RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp");
reqDispatcher.forward(request, response);

    B:2、通过request 对象提供的 getRequestDispatche(String path)方法,该方法返回一个RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。

request.getRequestDispatcher("/test.jsp").forward(request, response);
<body>
      使用普通方式取出存储在request对象中的数据:
      <h3 style="color:red;"><%=(String)request.getAttribute("data")%></h3>
     使用EL表达式取出存储在request对象中的数据:
     <h3 style="color:red;">${data}</h3>
  </body>

 2、通过response实现请求重定向

 /**
         * 1.调用sendRedirect方法实现请求重定向,
         * sendRedirect方法内部调用了
         * response.setHeader("Location", "/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
         * response.setStatus(HttpServletResponse.SC_FOUND);//设置302状态码,等同于response.setStatus(302);
         */
        response.sendRedirect("/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
        
        //2.使用response设置302状态码和设置location响应头实现重定向实现请求重定向
        //response.setHeader("Location", "/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
        //response.setStatus(HttpServletResponse.SC_FOUND);//设置302状态码,等同于response.setStatus(302);

 7、利用ServletContext对象读取资源文件

注意:通过类装载器读取资源文件的注意事项:不适合装载大文件,否则会导致jvm内存溢出
(1.1)使用类装载器读取资源文件【用类装载器读取src目录下的db1.properties配置文件】
  private void readPropFile(HttpServletResponse response) throws IOException {
        //获取到装载当前类的类装载器
        ClassLoader loader = ServletContextDemo7.class.getClassLoader();
        //用类装载器读取src目录下的db1.properties配置文件
        InputStream in = loader.getResourceAsStream("db1.properties");
        Properties prop = new Properties();
        prop.load(in);
        String driver = prop.getProperty("driver");
        String url = prop.getProperty("url");
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        response.getWriter().println("用类装载器读取src目录下的db1.properties配置文件:");
        response.getWriter().println(
                MessageFormat.format(
                        "driver={0},url={1},username={2},password={3}", 
                        driver,url, username, password));
    }

 (1.2)读取类路径下面、包下面的资源文件

//获取到装载当前类的类装载器
        ClassLoader loader = ServletContextDemo7.class.getClassLoader();
        //用类装载器读取src目录下的gacl.servlet.study包中的db4.properties配置文件
        InputStream in = loader.getResourceAsStream("gacl/servlet/study/db4.properties");
        Properties prop = new Properties();
        prop.load(in);
        String driver = prop.getProperty("driver");
        String url = prop.getProperty("url");
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        response.getWriter().println("用类装载器读取src目录下的gacl.servlet.study包中的db4.properties配置文件:");
        response.getWriter().println(
                MessageFormat.format(
                        "driver={0},url={1},username={2},password={3}", 
                        driver,url, username, password));
    }

 

(2)//读取src目录下的db.config包中的配置文件
 /**
     * 通过ServletContext对象读取src目录下的properties配置文件
     * @param response
     * @throws IOException
     */
    private void readSrcDirPropCfgFile(HttpServletResponse response) throws IOException {
        /**
         * 通过ServletContext对象读取src目录下的db1.properties配置文件
         */
        InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db1.properties");
        Properties prop = new Properties();
        prop.load(in);
        String driver = prop.getProperty("driver");
        String url = prop.getProperty("url");
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        response.getWriter().println("读取src目录下的db1.properties配置文件:");
        response.getWriter().println(
                MessageFormat.format(
                        "driver={0},url={1},username={2},password={3}", 
                        driver,url, username, password));
    }

 

(3)读取 src 下某个包中的配置文件【读取src目录下的gacl.servlet.study包中的db4.properties配置文件】
private void readPropCfgFile2(HttpServletResponse response)
            throws IOException {
        InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/gacl/servlet/study/db4.properties");
        Properties prop = new Properties();
        prop.load(in);
        String driver = prop.getProperty("driver");
        String url = prop.getProperty("url");
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        response.getWriter().println("读取src目录下的gacl.servlet.study包中的db4.properties配置文件:");
        response.getWriter().println(
                MessageFormat.format(
                        "driver={0},url={1},username={2},password={3}", 
                        driver,url, username, password));
    }

 (4)读取src目录下的db.config包中的db3.properties配置文件

//通过ServletContext获取web资源的绝对路径
        String path = this.getServletContext().getRealPath("/WEB-INF/classes/db/config/db3.properties");
        InputStream in = new FileInputStream(path);
        Properties prop = new Properties();
        prop.load(in);
        String driver = prop.getProperty("driver");
        String url = prop.getProperty("url");
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        response.getWriter().println("读取src目录下的db.config包中的db3.properties配置文件:");
        response.getWriter().println(
                MessageFormat.format(
                        "driver={0},url={1},username={2},password={3}", 
                        driver,url, username, password));
    }

 (5)通过ServletContext对象读取WebRoot目录下的properties配置文件

 /**
         * 通过ServletContext对象读取WebRoot目录下的properties配置文件
         * “/”代表的是项目根目录
         */
InputStream in = this.getServletContext().getResourceAsStream("/db2.properties"); Properties prop = new Properties(); prop.load(in); String driver = prop.getProperty("driver"); String url = prop.getProperty("url"); String username = prop.getProperty("username"); String password = prop.getProperty("password"); response.getWriter().println("读取WebRoot目录下的db2.properties配置文件:"); response.getWriter().print( MessageFormat.format( "driver={0},url={1},username={2},password={3}", driver,url, username, password)); }

 8、向浏览器输出中文数据

(1)response.getOutputStream() :得到输出 二进制数据 的 ServletOuputStream对象。

(2)response.getWriter()方法:得到、输出文本数据Printwriter对象。

(3)getOutputStream 和 getWriter这两个方法 互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。  

(4)Servlet 程序向 ServletOutputStream 或 PrintWriter 对象中写入的数据将被Servlet引擎从 response 里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。 

(5)Serlvet 的 service方法结束后,Servlet引擎将检查 getWriter 或 getOutputStream 方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象。

(8.1)以浏览器输出 binary data,字节流方式,需使用  OutputStream

在服务器端,数据是以哪个码表输出的,那么就要控制客户端浏览器以相应的码表打开。

比如:outputStream.write("中国".getBytes("UTF-8"));其意思是:使用OutputStream流向客户端浏览器输出中文,以UTF-8的编码进行输出;此时就要控制客户端浏览器以UTF-8的编码打开,否则显示的时候就会出现中文乱码。

那么在服务器端如何控制客户端浏览器以以UTF-8的编码显示数据呢?

(1)可以通过设置响应头控制浏览器的行为,例如:response.setHeader("content-type", "text/html;charset=UTF-8");其意思是:通过设置响应头控制浏览器以UTF-8的编码显示数据。

String data = "中国";
OutputStream outputStream = response.getOutputStream();//获取OutputStream输出流
//通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码
response.setHeader("content-type", "text/html;charset=UTF-8");
byte[] dataByteArr = data.getBytes("UTF-8");//将字符转换成字节数组,指定以UTF-8编码进行转换
    /**
         * data.getBytes()是一个将字符转换成字节数组的过程,这个过程中一定会去查码表,
         * 如果是中文的操作系统环境,默认就是查找查GB2312的码表,
         * 将字符转换成字节数组的过程就是将中文字符转换成GB2312的码表上对应的数字
         * 比如: "中"在GB2312的码表上对应的数字是98
         *         "国"在GB2312的码表上对应的数字是99
         */
        /**
//getBytes()方法如果不带参数,那么就会根据操作系统的语言环境来选择转换码表,如果是中文操作系统,那么就使用GB2312的码表
outputStream.write(dataByteArr);//使用OutputStream流向客户端输出字节数组

(8.2)使用PrintWriter流向客户端浏览器输出中文数据,字符流方式, character text

      使用PrintWriter流输出中文注意问题:

  在获取PrintWriter输出流之前 首先使用 "response.setCharacterEncoding(charset)" 设置字符以什么样的编码输出到浏览器

如:response.setCharacterEncoding("UTF-8");设置将字符以"UTF-8"编码输出到客户端浏览器,

然后再使用 response.getWriter(); 获取PrintWriter输出流,这两个步骤不能颠倒,如下:

response.setCharacterEncoding("UTF-8");//设置将字符以"UTF-8"编码输出到客户端浏览器
/**
* PrintWriter out = response.getWriter();这句代码必须放在response.setCharacterEncoding("UTF-8");之后
* 否则response.setCharacterEncoding("UTF-8")这行代码的设置将无效,浏览器显示的时候还是乱码
*/
PrintWriter out = response.getWriter();//获取PrintWriter输出流

然后再使用 response.setHeader("content-type", "text/html;charset=字符编码");设置响应头,控制浏览器以指定的字符编码编码进行显示,例如:

response.setHeader("content-type", "text/html;charset=UTF-8");
//通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码
/**
* 多学一招:使用HTML语言里面的<meta>标签来控制浏览器行为,模拟通过设置响应头控制浏览器行为
 *response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");
* 等同于response.setHeader("content-type", "text/html;charset=UTF-8");
*/
response.getWriter().write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");

具体实例:

public void outputChineseByPrintWriter(HttpServletResponse response) throws IOException{
        String data = "中国";
        
        //通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码
        //response.setHeader("content-type", "text/html;charset=UTF-8");
        
        response.setCharacterEncoding("UTF-8");//设置将字符以"UTF-8"编码输出到客户端浏览器
        /**
         * PrintWriter out = response.getWriter();这句代码必须放在response.setCharacterEncoding("UTF-8");之后
         * 否则response.setCharacterEncoding("UTF-8")这行代码的设置将无效,浏览器显示的时候还是乱码
         */
        PrintWriter out = response.getWriter();//获取PrintWriter输出流
        /**
         * 多学一招:使用HTML语言里面的<meta>标签来控制浏览器行为,模拟通过设置响应头控制浏览器行为
         * out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");
         * 等同于response.setHeader("content-type", "text/html;charset=UTF-8");
         */
        out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>");
        out.write(data);//使用PrintWriter流向客户端输出字符
    }
    
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

 9、response 文件下载

文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载

文件下载功能的实现思路:

  1.   获取要下载的文件的绝对路径
  2.   获取要下载的文件名
  3.   设置 content-disposition 响应头控制浏览器以下载的形式打开文件
  4.   获取要下载的文件输入流
  5.   创建数据缓冲区
  6.   通过 response 对象获取 OutputStream 流
  7.   将 FileInputStream 流写入到 buffer 缓冲区
  8.   使用 OutputStream 将缓冲区的数据输出到客户端浏览器
    /**
         * 下载文件,通过OutputStream流
         * @param response
         * @throws FileNotFoundException
         * @throws IOException
         */
        private void downloadFileByOutputStream(HttpServletResponse response)
                throws FileNotFoundException, IOException {
            //1.获取要下载的文件的绝对路径
            String realPath = this.getServletContext().getRealPath("/download/1.JPG");
            //2.获取要下载的文件名
            String fileName = realPath.substring(realPath.lastIndexOf("\")+1);
            //3.设置content-disposition响应头控制浏览器以下载的形式打开文件
            response.setHeader("content-disposition", "attachment;filename="+fileName);
    //需要注意的地方就是中文文件名要使用URLEncoder.encode方法进行编码(URLEncoder.encode(fileName, "字符编码")),否则会出现文件名乱码。
            response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
    //4.获取要下载的文件输入流 InputStream in = new FileInputStream(realPath); int len = 0; //5.创建数据缓冲区 byte[] buffer = new byte[1024]; //6.通过response对象获取OutputStream流 OutputStream out = response.getOutputStream(); //7.将FileInputStream流写入到buffer缓冲区 while ((len = in.read(buffer)) > 0) { //8.使用OutputStream将缓冲区的数据输出到客户端浏览器 out.write(buffer,0,len); } in.close(); }
原文地址:https://www.cnblogs.com/quietwalk/p/8609162.html