大家好,我是樂字節的小樂,上次給大家帶來了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乾貨資料和視頻。