八、Servlet 3.0注解

Servlet 3.0注解

在Servlet 3.0之后,為了簡(jiǎn)化Servlet開發(fā),Servlet的API,提供了注解,用于簡(jiǎn)化Servlet的配置。

常用注解如下:

注解 說(shuō)明
@WebServlet 用于取代Servlet的xml配置
@WebFilter 用于取代Filter的xml配置
@WebListener 用于取代Lsitener的xml配置
@WebInitParam 用于取代xml中初始化參數(shù)的配置
@MultipartConfig 用于標(biāo)識(shí)該Servlet支持文件上傳

@WebServlet

? name : 表示 servlet的名稱 默認(rèn)空字符串

? value/urlPatterns : 表示servlet的映射地址 格式是數(shù)組 表示servlet支持多個(gè)映射地址,直接可以在注解不聲明任何屬性,進(jìn)行賦值,值是默認(rèn)給value屬性。

loadOnStartup : servlet 初始化的時(shí)機(jī)

initParams : servlet初始化參數(shù) 值類型是:WebInitParam

@WebServlet(value = "test.do", loadOnStartup = 1, 
initParams = { @WebInitParam(name = "name1", value = "value1"),
        @WebInitParam(name = "name2", value = "value2") })
public class TestServlet extends HttpServlet {

    private static final long serialVersionUID = -4744875954442714537L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello  servlet  3.0");
    }
    
}

注意:

不推薦使用 initParams注解,雖然initParams能夠取代xml配置,但是實(shí)際上沒有任何意義。因?yàn)?strong>initParams可以通過(guò)@WebInitParam配置初始化參數(shù),但是這種配置方式是寫在類中,然后在方法里面,獲取配置對(duì)象ServletConfig進(jìn)行獲取值,再進(jìn)行相關(guān)操作。那么,為什么不直接在程序中使用這個(gè)值,而是獲取類上面的數(shù)據(jù)值?

@WebFilter

? filterName : filter的別名可以缺省

? value/urlPatterns : 過(guò)濾器過(guò)濾的地址規(guī)則

? servletNames : 過(guò)濾過(guò)濾的servlet的名稱 標(biāo)識(shí)這個(gè)filter 只過(guò)濾指定的servlet,其它請(qǐng)求不過(guò)濾

initParams :與servlet中的initParams參數(shù)一樣,標(biāo)識(shí)初始化參數(shù)

package com.sxt.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;


@WebFilter(value = {"/*"})
public class TestFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("攔截器");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        
    }

}

@WebListener

package com.sxt.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ApplicationListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("初始化");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("銷毀");
    }

}

@MultipartConfig

如果Servlet需要接收文件上傳的流數(shù)據(jù),需要在Servlet的類上面,使用@MultipartConfig注解進(jìn)行標(biāo)識(shí),

因?yàn)镾ervlet底層,會(huì)對(duì)請(qǐng)求的參數(shù),根據(jù)這個(gè)標(biāo)識(shí)進(jìn)行特殊封裝。

4.Servlet版文件上傳

在web中,實(shí)現(xiàn)文件上傳,有以下要求

  1. 提交數(shù)據(jù)的form表單,必須含有:enctype="multipart/form-data"

  2. form表單的提交請(qǐng)求的方式,必須是post請(qǐng)求

  3. 處理文件上傳的Servlet,必須使用@MultipartConfig注解修飾

文件上傳對(duì)相關(guān)API

package com.sxt.controller;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
 * @ClassName: UploadController 
 * @Description: 因?yàn)檫@個(gè)Servlet 要處理文件上傳的 文件數(shù)據(jù)  必須使用 @MultipartConfig 修飾
 * @author: Mr.T
 * @date: 2020年2月17日 下午4:14:23
 */
@WebServlet("/upload.do")
@MultipartConfig
public class UploadController extends HttpServlet {

    private static final long serialVersionUID = -5139866113909465871L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 注意 輸入框的數(shù)據(jù)   輸入框是普通的文本數(shù)據(jù)
        String fileName = req.getParameter("fileName");
        System.out.println("輸入框的數(shù)據(jù):"+fileName);
        //獲取文件流數(shù)據(jù)  使用getPart("name")
        //此時(shí) 返回  part 對(duì)象  這個(gè)part 里面封裝了所有跟文件數(shù)據(jù)相關(guān)數(shù)據(jù)
        Part part = req.getPart("file");
        //文件的大小
        System.out.println(part.getSize());
        //文件類型的請(qǐng)求頭的中的值  : 例如 : map3 具體格式   --媒體類型 :audio/mpeg
        System.out.println(part.getContentType());
        //此時(shí)getName  是獲取表單中 input的name屬性值 沒有意義  不是文件的名稱
        String name = part.getName();
        System.out.println("input中的name值:"+name);
        //獲取 上傳的文件數(shù)據(jù)流
        //既然part 已經(jīng)提供了持久化的方法  為了還提供一個(gè)獲取輸入流數(shù)據(jù)的方法?
        //因?yàn)?此時(shí)當(dāng)前輸入流中的數(shù)據(jù)就是整個(gè)文件的流數(shù)據(jù),可以輸出到任何地方。
        //更加靈活,注意  inputStream 也支持保存到本地
        InputStream in = part.getInputStream();
        /*
        byte[] b = new byte[1024];
        int len = -1;
        FileOutputStream  fos = new FileOutputStream("F:\\2.jpg");
        while((len = in.read(b)) != -1) {
            fos.write(b, 0, len);
            fos.flush();
        }
        fos.close();
        in.close();
        */
        //如何獲取文件的真實(shí)名稱 和文件后綴 
        // 獲取上傳數(shù)據(jù)的對(duì)應(yīng)的請(qǐng)求頭信息  
        // 根據(jù) Content-Disposition 整個(gè)請(qǐng)求頭  獲取上傳文件的名稱相關(guān)信息
        String header = part.getHeader("Content-Disposition");
        //form-data; name="file"; filename="2.jpeg"
        //現(xiàn)在需要獲取字符串中 : filename = 后面的值
        System.out.println("文件的真實(shí)名稱:"+getFileName(part));
        System.out.println("文件真實(shí)名稱相關(guān)信息:"+header);
        //將上傳的文件數(shù)據(jù)進(jìn)行持久化
        part.write("F:\\1.jpg");
    }
    
    
    /**
     * @Title: getFileName
     * @author: Mr.T   
     * @date: 2020年2月17日 下午4:48:49 
     * @Description: 獲取文件的原名稱
     * @param part
     * @return
     * @return: String
     */
    private String  getFileName(Part part) {
        // 由于文件的原名稱 在請(qǐng)求頭中
        String header = part.getHeader("Content-Disposition");
        //form-data; name="file"; filename="2.jpeg"
        String[] info = header.split(" ");
        //從數(shù)組中獲取原名稱相關(guān)信息 :filename="2.jpeg"
        String name = info[2].trim();
        name = name.substring(10 , name.length() - 1);
        return name;
    }
}

文件上傳的路徑問題

package com.sxt.controller;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
 * @ClassName: UploadController 
 * @Description: 因?yàn)檫@個(gè)Servlet 要處理文件上傳的 文件數(shù)據(jù)  必須使用 @MultipartConfig 修飾
 * @author: Mr.T
 * @date: 2020年2月17日 下午4:14:23
 */
@WebServlet("/upload2.do")
@MultipartConfig
public class UploadController2 extends HttpServlet {

    private static final long serialVersionUID = -5139866113909465871L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 注意 輸入框的數(shù)據(jù)   輸入框是普通的文本數(shù)據(jù)
        String fileName = req.getParameter("fileName");
        System.out.println("輸入框的數(shù)據(jù):"+fileName);
        //獲取文件流數(shù)據(jù)  使用getPart("name")
        //此時(shí) 返回  part 對(duì)象  這個(gè)part 里面封裝了所有跟文件數(shù)據(jù)相關(guān)數(shù)據(jù)
        Part part = req.getPart("file");
     
        //將圖片保存在F盤,沒有問題,但是此時(shí)圖片不能查看。因?yàn)镕盤不在tomcat 服務(wù)器中,
        //瀏覽器只能訪問到項(xiàng)目的目錄中的文件
        //而目前F 盤 不屬于項(xiàng)目的中文件夾,所以瀏覽器是訪問不到的。
        //所以一般圖片需要保存在服務(wù)器中: 保存在服務(wù)器中,就會(huì)有2個(gè)路徑。
        //1. 文件的物理路徑    是具體保存文件的路徑  用于文件下載
        //2. 文件的網(wǎng)絡(luò)訪問路徑   是用于在瀏覽器中訪問這個(gè)文件的路徑
        // 要將文件保存到物理磁盤上,所以要有文件的物理路徑
        //獲取img的物理路徑 
        String realPath = req.getServletContext().getRealPath("img");
        //生成文件的物理路徑
        // File.separator 路徑分割符    因?yàn)椴煌牟僮飨到y(tǒng)  分割符存在差異    win \  linux /
        String filePath = realPath + File.separator + getFileName(part);
        System.out.println("文件具體保存路徑:"+filePath);
        //保存文件
        part.write(filePath);
        //要有圖片的URL地址  網(wǎng)絡(luò)訪問路徑
        String url = "/img/"+getFileName(part);
        System.out.println(url);
        //注意: 保存的文件名稱  不建議使用 文件的原名稱,因?yàn)榭赡艹霈F(xiàn)覆蓋,
        //所以一般保存的文件名稱有一套生成文件名稱的策略
        // 如: 使用UUID作為文件名稱
        // 如:時(shí)間戳+隨機(jī)數(shù)  作為文件名稱  等等 
    }
    
    
    /**
     * @Title: getFileName
     * @author: Mr.T   
     * @date: 2020年2月17日 下午4:48:49 
     * @Description: 獲取文件的原名稱
     * @param part
     * @return
     * @return: String
     */
    private String  getFileName(Part part) {
        // 由于文件的原名稱 在請(qǐng)求頭中
        String header = part.getHeader("Content-Disposition");
        //form-data; name="file"; filename="2.jpeg"
        String[] info = header.split(" ");
        //從數(shù)組中獲取原名稱相關(guān)信息 :filename="2.jpeg"
        String name = info[2].trim();
        name = name.substring(10 , name.length() - 1);
        return name;
    }
    

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容