Java註解-註解處理器、servlet3.0|樂字節

大家好,我是樂字節的小樂,上次給大家帶來了Java註解-元數據、註解分類、內置註解和自定義註解|樂字節,這次接着往下講註解處理器和servlet3.0
圖片描述

一、註解處理器

使用註解的過程中,很重要的一部分就是創建於使用註解處理器。Java SE5擴展了反射機制的API,以幫助程序員快速的構造自定義註解處理器。

1、註解處理器類庫java.lang.reflect.AnnotatedElement

Java使用Annotation接口來代表程序元素前面的註解,該接口是所有Annotation類型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,該接口代表程序中可以接受註解的程序元素,該接口主要有如下幾個實現類:

Class:類定義
Constructor:構造器定義
Field:累的成員變量定義
Method:類的方法定義
Package:類的包定義

java.lang.reflect 包下主要包含一些實現反射功能的工具類,實際上,java.lang.reflect 包所有提供的反射API擴充了讀取運行時Annotation信息的能力。當一個Annotation類型被定義爲運行時的Annotation後,該註解才能是運行時可見,當class文件被裝載時被保存在class文件中的Annotation纔會被虛擬機讀取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了某個類的AnnotatedElement對象之後,程序就可以調用該對象的如下四個個方法來訪問Annotation信息:

①<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回該程序元素上存在的、指定類型的註解,如果該類型註解不存在,則返回null。

②Annotation[] getAnnotations():返回該程序元素上存在的所有註解。

③boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的註解,存在則返回true,否則返回false.

④Annotation[] getDeclaredAnnotations():返回直接存在於此元素上的所有註釋。與此接口中的其他方法不同,該方法將忽略繼承的註釋。(如果沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)該方法的調用者可以隨意修改返回的數組;這不會對其他調用者返回的數組產生任何影響。

2、解析實例

public class ParseCoder {
    public static void main(String[] args) {
        String coderName="名稱:";
        String coderType="類型:";
        String coderProvider="廠家信息如下 ";
        Field [] fields=Coder.class.getDeclaredFields();
        for(Field field:fields){
            if(field.isAnnotationPresent(Programmer.class)){
                Programmer pro=(Programmer)field.getAnnotation(Programmer.class);
                coderName=coderName+pro.value();
                System.out.println(coderName);
            }else if(field.isAnnotationPresent(ProgrammerType.class)){
                ProgrammerType type=(ProgrammerType)field.getAnnotation(ProgrammerType.class);
                coderType=coderType+type.type().toString();
                System.out.println(coderType);
            }else if(field.isAnnotationPresent(ProgrammerProductor.class)){
                ProgrammerProductor fruitProvider=(ProgrammerProductor)field.getAnnotation(ProgrammerProductor.class);
                coderProvider+="編號:"+fruitProvider.id()+" 名稱:"+fruitProvider.name()+" 地址:"+fruitProvider.address();
                System.out.println(coderProvider);
            }
        }
    }
}

二、 Servlet3.0

1、@WebServlet

使用註解達到零配置,開發servlet項目,使用@WebServlet將一個繼承於javax.servlet.http.HttpServlet的類定義爲Servlet組件。在Servlet3.0中,可以使用@WebServlet註解將一個繼承於javax.servlet.http.HttpServlet的類標註爲可以處理用戶請求的Servlet。

@WebServlet註解的相關屬性

圖片描述

Servlet的訪問URL是Servlet的必選屬性,可以選擇使用urlPatterns或者value定義。如一個Servlet可以描述成:

@WebServlet(name="ServletDemo",value="/ServletDemo")。

也定義多個URL訪問:如

@WebServlet(name="ServletDemo",urlPatterns={"/ServletDemo","/ServletDemo2"})

或者:

@WebServlet(name="AnnotationServlet",value={"/ServletDemo","/ServletDemo2"})

initParams可以用來指定當前Servlet的初始化參數,它是一個數組, 裏面每一個@WebInitParam表示一個參數。

@WebServlet(value="/servlet/init-param", initParams={@WebInitParam(name="param1", value="value1")})

測試實例如下

/**
 * 使用@WebServlet將一個繼承於javax.servlet.http.HttpServlet的類定義爲Servlet組件。
如@WebServlet有很多的屬性:
1、asyncSupported:    聲明Servlet是否支持異步操作模式。
2、description:      Servlet的描述。
3、displayName:       Servlet的顯示名稱。
4、initParams:        Servlet的init參數。
5、name:           Servlet的名稱。
6、urlPatterns:Servlet的訪問URL。
7、value:           Servlet的訪問URL。
Servlet的訪問URL是Servlet的必選屬性,可以選擇使用urlPatterns或者value定義。
如@WebServlet(name="TestServlet",value="/TestServlet"),也定義多個URL訪問:
如@WebServlet(name="TestServlet",urlPatterns={"/TestServlet","/Test"})
或@WebServlet(name="TestServlet",value={"/TestServlet","/Test"})
 */
@WebServlet(name="/TestServlet",urlPatterns={"/test"})
public class TestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("hello servlet3");
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

初始化參數

@WebServlet(value="/init", 
initParams={@WebInitParam(name="param1", value="sxt")})
public class TestInit extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      Enumeration<String> paramNames = this.getServletConfig().getInitParameterNames();  
      String paramName;  
      while (paramNames.hasMoreElements()) {  
         paramName = paramNames.nextElement();  
         response.getWriter().append(paramName + " = " + this.getServletConfig().getInitParameter(paramName));  
      }  
      response.getWriter().close();  
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

2、@WebFilter

/**
 * 使用註解標註過濾器:@WebFilter將一個實現了javax.servlet.Filter
 * 接口的類定義爲過濾器,屬性filterName聲明過濾器的名稱,可選
 * 屬性urlPatterns指定要過濾 的URL模式,也可使用屬性value來聲明.
 * (指定要過濾的URL模式是必選屬性),
 * 可以指定多種過濾模式@WebFilter(filterName="TestFilter",
 * urlPatterns={"/User","/index.jsp"})
 * @author Administrator
 */
@WebFilter(filterName="TestFilter",urlPatterns="/*")
public class TestFilter implements Filter  {
    @Override
    public void destroy() {
        System.out.println("過濾器銷燬");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("執行過濾操作");
        chain.doFilter(request, response);
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
         System.out.println("過濾器初始化");
    }
}

3、@MultipartConfig

使用註解@MultipartConfig將一個Servlet標識爲支持文件上傳。Servlet3.0將multipart/form-data的POST請求封裝成Part,通過Part對上傳的文件進行操作。

注意:Servlet3沒有提供直接獲取文件名的方法,需要從請求頭中解析出來

1)、頁面製作

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上傳</title>
</head>
<body>
    <fieldset>
        <legend>上傳文件</legend>
        <!-- 文件上傳時必須要設置表單的enctype="multipart/form-data" -->
        <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
            上傳文件:<input type="file" name="file1"><br/>
            上傳文件:<input type="file" name="file2"><br/>
            <input type="submit" value="上傳">
        </form>
    </fieldset>
</body>
</html>

2)、編寫Servlet

/**
 * Servlet3.0將multipart/form-data的POST請求封裝成Part,
 * 通過Part對上傳的文件進行操作,Servlet3沒有提供直接獲取文件名的方法,
 * 需要從請求頭中解析出來,獲取請求頭,請求頭的格式:
 * 火狐和google瀏覽器下:form-data; name="file"; filename="snmp4j--api.zip"
* @author Administrator
 */
@WebServlet(name = "TestUpload", urlPatterns = "/upload")
@MultipartConfig
public class TestUpload extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        // 存儲路徑
String savePath = request.getServletContext().getRealPath("/WEB-INF/upload");
        // 獲取上傳的文件集合
        Collection<Part> parts = request.getParts();
        //上傳單個文件
        if (parts.size()==1) {
            //通過文件名獲取文件
            Part part = request.getPart("file");
            //從請求頭中獲取文件
            String header = part.getHeader("content-disposition");
            //獲取文件名
            String fileName = getFileName(header);
            //把文件寫到指定路徑
            part.write(savePath+File.separator+fileName);
        }else{
             for (Part part : parts) {//循環處理上傳的文件
//請求頭的格式:form-data; name="file"; filename="snmp4j--api.zip"
                 String header = part.getHeader("content-disposition");
                 //獲取文件名
String fileName = getFileName(header);
                if(!fileName.equals("")){
                    //把文件寫到指定路徑
                    part.write(savePath+File.separator+fileName);
                }                 
             }
        }
        PrintWriter out = response.getWriter();
        out.println("上傳成功");
        out.flush();
        out.close();
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
    /**
     * 獲取文件名
* 火狐和google瀏覽器下:form-data; name="file"; filename="snmp4j--api.zip"
     * @param header
     * @return
     */
    private  String getFileName(String header) {
        String[] headArr = header.split(";")[2].split("=");
        //獲取文件名,兼容各種瀏覽器的寫法        
        return headArr[1].substring(headArr[1].lastIndexOf("\\")+1).replaceAll("\"", "");
        
    }
}

4、@WebListener

Servlet3.0提供@WebListener註解將一個實現了特定監聽器接口的類定義爲監聽器。將實現了ServletContextListener接口的MyServletContextListener標註爲監聽器。

@WebListener
public class TestListener implements ServletContextListener {
    @Override
    public void contextDestroyed(ServletContextEvent event) {
         System.out.println("ServletContext銷燬");
    }
    @Override
    public void contextInitialized(ServletContextEvent event) {
         System.out.println("ServletContex初始化");
         System.out.println(event.getServletContext().getServerInfo());
    }
}

有關注解就介紹到這裏了,感謝各位老闆的光顧和學習。

請繼續關注樂字節,後續不斷更新Java乾貨資料和視頻。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章