Servlet 3.0注解
在Servlet 3.0之后摄咆,為了簡(jiǎn)化Servlet開(kāi)發(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的名稱(chēng) 默認(rèn)空字符串
? value/urlPatterns : 表示servlet的映射地址 格式是數(shù)組 表示servlet支持多個(gè)映射地址恶迈,直接可以在注解不聲明任何屬性涩金,進(jìn)行賦值,值是默認(rèn)給value屬性暇仲。
loadOnStartup : servlet 初始化的時(shí)機(jī)
initParams : servlet初始化參數(shù) 值類(lèi)型是: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í)際上沒(méi)有任何意義熔吗。因?yàn)?strong>initParams可以通過(guò)@WebInitParam配置初始化參數(shù)辆床,但是這種配置方式是寫(xiě)在類(lèi)中,然后在方法里面,獲取配置對(duì)象ServletConfig進(jìn)行獲取值桅狠,再進(jìn)行相關(guān)操作讼载。那么,為什么不直接在程序中使用這個(gè)值中跌,而是獲取類(lèi)上面的數(shù)據(jù)值?
@WebFilter
? filterName : filter的別名可以缺省
? value/urlPatterns : 過(guò)濾器過(guò)濾的地址規(guī)則
? servletNames : 過(guò)濾過(guò)濾的servlet的名稱(chēng) 標(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("銷(xiāo)毀");
}
}
@MultipartConfig
如果Servlet需要接收文件上傳的流數(shù)據(jù)漩符,需要在Servlet的類(lèi)上面一喘,使用@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)文件上傳萎战,有以下要求:
提交數(shù)據(jù)的form表單,必須含有:enctype="multipart/form-data"
form表單的提交請(qǐng)求的方式舆逃,必須是post請(qǐng)求
處理文件上傳的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());
//文件類(lèi)型的請(qǐng)求頭的中的值 : 例如 : map3 具體格式 --媒體類(lèi)型 :audio/mpeg
System.out.println(part.getContentType());
//此時(shí)getName 是獲取表單中 input的name屬性值 沒(méi)有意義 不是文件的名稱(chēng)
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í)名稱(chēng) 和文件后綴
// 獲取上傳數(shù)據(jù)的對(duì)應(yīng)的請(qǐng)求頭信息
// 根據(jù) Content-Disposition 整個(gè)請(qǐng)求頭 獲取上傳文件的名稱(chēng)相關(guān)信息
String header = part.getHeader("Content-Disposition");
//form-data; name="file"; filename="2.jpeg"
//現(xiàn)在需要獲取字符串中 : filename = 后面的值
System.out.println("文件的真實(shí)名稱(chēng):"+getFileName(part));
System.out.println("文件真實(shí)名稱(chēng)相關(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: 獲取文件的原名稱(chēng)
* @param part
* @return
* @return: String
*/
private String getFileName(Part part) {
// 由于文件的原名稱(chēng) 在請(qǐng)求頭中
String header = part.getHeader("Content-Disposition");
//form-data; name="file"; filename="2.jpeg"
String[] info = header.split(" ");
//從數(shù)組中獲取原名稱(chēng)相關(guān)信息 :filename="2.jpeg"
String name = info[2].trim();
name = name.substring(10 , name.length() - 1);
return name;
}
}
文件上傳的路徑問(wèn)題:
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盤(pán),沒(méi)有問(wèn)題,但是此時(shí)圖片不能查看虫啥。因?yàn)镕盤(pán)不在tomcat 服務(wù)器中,
//瀏覽器只能訪問(wèn)到項(xiàng)目的目錄中的文件
//而目前F 盤(pán) 不屬于項(xiàng)目的中文件夾,所以瀏覽器是訪問(wèn)不到的。
//所以一般圖片需要保存在服務(wù)器中: 保存在服務(wù)器中,就會(huì)有2個(gè)路徑奄妨。
//1. 文件的物理路徑 是具體保存文件的路徑 用于文件下載
//2. 文件的網(wǎng)絡(luò)訪問(wèn)路徑 是用于在瀏覽器中訪問(wèn)這個(gè)文件的路徑
// 要將文件保存到物理磁盤(pán)上,所以要有文件的物理路徑
//獲取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ò)訪問(wèn)路徑
String url = "/img/"+getFileName(part);
System.out.println(url);
//注意: 保存的文件名稱(chēng) 不建議使用 文件的原名稱(chēng)涂籽,因?yàn)榭赡艹霈F(xiàn)覆蓋,
//所以一般保存的文件名稱(chēng)有一套生成文件名稱(chēng)的策略
// 如: 使用UUID作為文件名稱(chēng)
// 如:時(shí)間戳+隨機(jī)數(shù) 作為文件名稱(chēng) 等等
}
/**
* @Title: getFileName
* @author: Mr.T
* @date: 2020年2月17日 下午4:48:49
* @Description: 獲取文件的原名稱(chēng)
* @param part
* @return
* @return: String
*/
private String getFileName(Part part) {
// 由于文件的原名稱(chēng) 在請(qǐng)求頭中
String header = part.getHeader("Content-Disposition");
//form-data; name="file"; filename="2.jpeg"
String[] info = header.split(" ");
//從數(shù)組中獲取原名稱(chēng)相關(guān)信息 :filename="2.jpeg"
String name = info[2].trim();
name = name.substring(10 , name.length() - 1);
return name;
}
}