Servlet介紹
概述
Servlet是運行在服務(wù)器端的Java應(yīng)用程序
servlet程序開發(fā)動態(tài)資源的技術(shù)
Servlet(Server Applet)是Java Servlet的簡稱,稱為小服務(wù)程序或服務(wù)連接器,
用Java編寫的服務(wù)器端程序,主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動態(tài)Web內(nèi)容。
作用:
用于接收和處理http請求(接收和響應(yīng)請求)
最核心的方法
void service(ServletRequest req,ServletResponse res)
ServletRequest req 代表請求對象,包含請求的所有內(nèi)容,用于獲取請求數(shù)據(jù)
ServletResponse res 代表響應(yīng)對象,包含響應(yīng)的所有內(nèi)容,用于修改響應(yīng)數(shù)據(jù)
Servlet開發(fā)步驟
1)java類,繼承HttpServlet類
覆蓋doGet和doPost方法
2)在web應(yīng)用web.xml中配置servlet
3)請求Servlet
創(chuàng)建Servlet
//第一種方式 繼承 GenericServlet
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class OneServlet extends GenericServlet {
private static final long serialVersionUID = -2949013647446695209L;
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
}
}
//第二種方式 繼承 HttpServlet
//繼承自GenericServlet類,是在其基礎(chǔ)上擴展了Http協(xié)議的Servlet
//會先調(diào)用service方法,然后根據(jù)請求方式來進(jìn)行調(diào)用doGet/doPost
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class OneServlet extends HttpServlet {
private static final long serialVersionUID = -4435501112176421548L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
配置Servlet
在web.xml中配置
<servlet>
<!-- 名稱要唯一 -->
<servlet-name>one</servlet-name>
<!-- 全路徑 -->
<servlet-class>com.shuai.action.OneServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 要與上邊的名稱一致 -->
<servlet-name>one</servlet-name>
<!-- 訪問Servlet的URL,相對于Web應(yīng)用的路徑 -->
<url-pattern>/one</url-pattern>
</servlet-mapping>
配置Servlet中設(shè)置初始化值
<servlet>
<servlet-name>one</servlet-name>
<servlet-class>com.shuai.action.OneServlet</servlet-class>
<!-- 設(shè)置初始化值 -->
<init-param>
<param-name>initParam</param-name>
<param-value>paramtest</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>one</servlet-name>
<url-pattern>/one</url-pattern>
</servlet-mapping>
@Override
public void init(ServletConfig config) throws ServletException {
//這個super一定不要刪掉
super.init(config);
//通過ServletConfig對象讀取初始化參數(shù)
String initParameter = config.getInitParameter("initParam");
System.out.println(initParameter);
//獲得所有參數(shù)的key
Enumeration<String> enumeration = config.getInitParameterNames();
}
有參的init 與 無參init
有參init:生命周期方法,必定會被服務(wù)器調(diào)用。(內(nèi)部默認(rèn)會調(diào)用無參的init方法)
無參init:提供給開發(fā)者進(jìn)行初始化工作的方法。
Servlet生命周期
實例化 - Servlet 容器創(chuàng)建 Servlet 的實例
初始化 - 容器調(diào)用 init() 方法
請求處理 - 如果請求 Servlet,則容器調(diào)用 service() 方法
服務(wù)終止/重新部署 - 銷毀實例之前調(diào)用 destroy() 方法,通過stop server看
Servlet線程安全問題
Servlet 在服務(wù)器中是單實例多線程的。
每次都會在Service方法中新建一個子線程來處理請求:new ThreadServlet()
引起并發(fā)問題的原因:在Servlet中使用了成員變量(多個線程共享的數(shù)據(jù))。
測試:
可以通過在Servlet中輸出一個count值,然后線程睡眠,最后count++。
用兩個瀏覽器同時去訪問。會發(fā)現(xiàn)最后輸出的結(jié)果是一樣的。
解決多并發(fā),用同步
在doGet方法中
synchronized (OneServlet.class) {
//業(yè)務(wù)代碼
}
建議:
盡量不要在Servlet中使用成員變量
如果使用了成員變量,那么就需要使用synchronized進(jìn)行同步代碼,而且盡量縮小同步的范圍
Servlet的一些細(xì)節(jié)
改變Servlet的創(chuàng)建時機
<servlet>
<servlet-name>one</servlet-name>
<servlet-class>com.shuai.action.ThreeServlet</servlet-class>
<!-- 在項目部署啟動的時候,默認(rèn)創(chuàng)建Servlet,數(shù)值越大優(yōu)先級越低 -->
<load-on-startup>1</load-on-startup>
</servlet>
路徑映射規(guī)則
url-pattern 頁面訪問
精確映射 /one /one
/test/one /test/one
模糊映射 /* /任意路徑
/test/* /test/任意路徑
*.后綴 任意路徑.后綴
注意:
url-pattern要么以/或者*開頭
當(dāng)前有多個url-pattern,優(yōu)先級問題
后綴名結(jié)尾的url-pattern優(yōu)先級最低
哪個更加精確哪個優(yōu)先
ServletConfig對象
概述
Servlet配置對象
作用
用于讀取servlet參數(shù)
如何得到ServletConfig對象
通過有參的init方法獲得
通過getServletConfig()獲得
ServletContext對象
概述
ServletContext是servlet的上下文對象。
代表當(dāng)前web應(yīng)用。
一個web有且只有一個ServletContext對象。
獲取ServletContext對象
ServletContext servletContext = getServletConfig().getServletContext();
ServletContext servletContext = getServletContext();
作用
作為全局的域?qū)ο笫褂? 讀取全局的配置參數(shù)
轉(zhuǎn)發(fā)web應(yīng)用內(nèi)的資源
讀取web應(yīng)用內(nèi)的文件
具體使用
設(shè)置全局屬性參數(shù)
ServletContext servletContext = getServletContext();
servletContext.setAttribute("name", "zhangsan");
String str = (String)servletContext.getAttribute("name");
讀取全局參數(shù)
<!-- 全局參數(shù) -->
<context-param>
<param-name>onep</param-name>
<param-value>onep</param-value>
</context-param>
<context-param>
<param-name>twop</param-name>
<param-value>twop</param-value>
</context-param>
ServletContext servletContext = getServletContext();
String onep = servletContext.getInitParameter("onep");
String twop = servletContext.getInitParameter("twop");
轉(zhuǎn)發(fā)
ServletContext servletContext = getServletContext();
//轉(zhuǎn)發(fā)內(nèi)部資源
RequestDispatcher dispatcher = servletContext.getRequestDispatcher("info.jsp");
dispatcher.forward(req, res);
讀取web應(yīng)用內(nèi)的文件
ServletContext servletContext = getServletContext();
//獲取一個文件的絕對路徑 - 獲取的項目根目錄
//要以/開頭
String realPath = servletContext.getRealPath("/");
System.out.println(realPath);
//讀取一個文件,并且返回一個文件流
InputStream inputStream = servletContext.getResourceAsStream("/路徑");
HttpServletResponse對象
response對象
表示響應(yīng)對象,包含所有的響應(yīng)數(shù)據(jù)。使用response對象可以修改響應(yīng)數(shù)據(jù)。
響應(yīng)格式
響應(yīng)行
http版本
狀態(tài)碼 setStatus(sc)方法
描述
響應(yīng)頭
鍵值對
setHeader(key,value)方法
setDateHeader(key,value)方法-專門修改日期類型的響應(yīng)頭
setIntHeader(key,value)方法 - 專門修改int類型的響應(yīng)頭
空行
正文
getWriter() 修改字符類型的正文(文本,網(wǎng)頁)minetype:text/*類型
getOutputStream() 修改字節(jié)類型的正文(圖片,視頻)
getOutputStream()返回文本數(shù)據(jù)解決亂碼
系統(tǒng)默認(rèn)是GBK
ServletOutputStream outputStream = res.getOutputStream();
String str = "帥哥";
outputStream.write(str.getBytes());
輸出其它編碼
ServletOutputStream outputStream = res.getOutputStream();
第一種方式
僅僅在ie瀏覽器有效
String meta = "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
//String meta = "<meta charset='UTF-8'>";
outputStream.write(meta.getBytes());
第二種方式
所有瀏覽器有效
response.setHeader("content-type", "text/html; charset=UTF-8");
第三種方式
所有瀏覽器有效
response.setContentType("text/html; charset=UTF-8");
String str = "帥哥";
outputStream.write(str.getBytes("UTF-8"));
getWriter()返回文本數(shù)據(jù)解決亂碼
write方法默認(rèn)是iso-8859-1
只能輸出字節(jié)
輸出其它編碼
修改輸出字符內(nèi)容的查詢編碼-修改的是服務(wù)器- 這個代碼可以省略
response.setCharacterEncoding("UTF-8");
通知瀏覽器使用正確的編碼解析
response.setContentType("text/html; charset=UTF-8");
PrintWriter writer = response.getWriter();
默認(rèn)編碼是iso-8859-1
writer.write("帥哥");
文件下載
讀取文件
String path = getServletContext().getRealPath("/file/開發(fā)0710學(xué)生情況.xlsx");
File file = new File(path);
FileInputStream inputStream = new FileInputStream(file);
獲取輸出通道
ServletOutputStream outputStream = response.getOutputStream();
下載提示框 響應(yīng)頭 content-disposition
注意:在瀏覽器和服務(wù)器之間請求頭和響應(yīng)頭內(nèi)容出現(xiàn)中文,不能直接傳輸,而應(yīng)該把中文內(nèi)容進(jìn)行URL編碼才能傳輸
String filename = URLEncoder.encode(file.getName(),"UTF-8");
response.setHeader("content-disposition", "attachment;filename="+filename);
邊讀邊寫
byte[] buf = new byte[1024];
int len = 0;
while((len =inputStream.read(buf))!= -1){
outputStream.write(buf);
}
關(guān)閉流
inputStream.close();
輸出隨機驗證碼(防止惡意注冊和登錄)
public void writeImage(HttpServletResponse response)throws ServletException, IOException {
//內(nèi)存生成一張圖片
int width = 120;
int height = 50;
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//修改圖片背景
//得到畫筆
Graphics graphics = image.getGraphics();
//繪制背景
graphics.setColor(Color.gray);
//繪制形狀
graphics.fillRect(0, 0, width, height);
//設(shè)置字體
graphics.setFont(new Font("黑體", Font.ITALIC, 30));
//繪制數(shù)字
graphics.setColor(Color.BLACK);
String str = "1234";
graphics.drawString(str, 20, 25);
//設(shè)置隨機干擾線
Random ran = new Random();
for(int i=1;i<=20;i++){
int x1 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int x2 = ran.nextInt(width);
int y2 = ran.nextInt(height);
//隨機色
graphics.setColor(getRanColor());
graphics.drawLine(x1, y1, x2, y2);
}
//把這個圖片寫出給瀏覽器
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "gif", outputStream);
}
//獲取隨機顏色
private Color getRanColor(){
Random ran = new Random();
int r = ran.nextInt(256);
int g = ran.nextInt(256);
int b = ran.nextInt(256);
return new Color(r,g,b);
}
頁面使用

重定向
發(fā)出兩次請求
地址欄會發(fā)生變化
可以重定向任何資源(包括應(yīng)用外的資源)
不可以通過request來共享數(shù)據(jù)
代碼
response.sendRedirect("/info.jsp");
HttpServletRequest對象
概述
表示請求對象,包含所有的請求數(shù)據(jù)。使用request獲取請求的數(shù)據(jù)。
請求格式
請求行
請求方式 request.getMethod()
請求資源 request.getRequestURL() / request.getRequestURI()
http版本 request.getProtocol()
獲得get請求的參數(shù) request.getQueryString()
請求頭
獲得一個請求頭 getHeader(key)
獲得整形的請求頭 getIntHeader(key)
獲得日期類型的請求頭 getDateHeader(key)
空行
正文
獲得正文 getInputStream()
防盜鏈
String referer = request.getHeader("referer");
if(referer == null || !referer.contains("/servlettest")){
//非法連接
return;
}
獲取表單數(shù)據(jù)
get : getQueryString()
post : getInputStream()
通用方式
獲取某個參數(shù) getParameter("")
獲取某個參數(shù)的集合 getParameterValues("") 例如:checkbox
獲取所有的參數(shù)名 getParameterNames()
獲取所有的參數(shù) getParameterMap()
亂碼問題
if("post".equalsIgnoreCase(request.getMethod())){
//只能解決post提交的參數(shù),不能解決get提交的參數(shù),因為這個方法只能設(shè)置請求正文的內(nèi)容
request.setCharacterEncoding("UTF-8");
}
String name = request.getParameter("name");//默認(rèn)是iso-8859-1
if("get".equalsIgnoreCase(request.getMethod())){
//get請求的參數(shù)需要手動解碼
name = new String(name.getBytes("iso-8859-1"),"UTF-8");
}
轉(zhuǎn)發(fā)
發(fā)出一次請求
地址欄不會發(fā)生變化
只能轉(zhuǎn)發(fā)應(yīng)用內(nèi)的資源
可以通過request來共享數(shù)據(jù)
代碼
//可以把數(shù)據(jù)發(fā)到轉(zhuǎn)發(fā)的頁面
req.setAttribute("name", "zhangshuai");
//第一種方式
getServletContext().getRequestDispatcher("/info.jsp").forward(req, response);
//第二種方式
req.getRequestDispatcher("/info.jsp").forward(req, response);
beanutils封裝參數(shù)
下載
https://commons.apache.org/proper/commons-beanutils/
http://commons.apache.org/proper/commons-logging/ 依賴包
導(dǎo)包
commons-beanutils-1.9.3.jar
commons-logging-1.2.jar
頁面
<form action="/easyuitest/one" method="post">
用戶名:<input type="text" name="name" /><br />
密碼:<input type="password" name="password" /><br />
愛好: <input type="checkbox" name="hobby" value="eat" />吃
<input type="checkbox" name="hobby" value="sleep" />睡
<input type="checkbox" name="hobby" value="play" />玩<br />
<input type="submit" value="提交" />
</form>
后臺工具類
public static <T> T transform(Class clazz, HttpServletRequest req) throws Exception {
String method = req.getMethod();
if ("post".equalsIgnoreCase(method)) {
req.setCharacterEncoding("UTF-8");
}
Object instance = null;
instance = clazz.newInstance();
BeanUtils.populate(instance, req.getParameterMap());
if ("get".equalsIgnoreCase(method)) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
char charAt = name.charAt(0);
String upperCase = String.valueOf(charAt).toUpperCase();
String name2 = "set" + upperCase + name.substring(1);
String name1 = "get" + upperCase + name.substring(1);
Method method2 = clazz.getMethod(name2, field.getType());
Method method3 = clazz.getMethod(name1);
Class type = field.getType();
Class s = String.class;
String invoke = (String) method3.invoke(instance);
if (s.equals(type)) {
invoke = new String(invoke.getBytes("iso-8859-1"), "UTF-8");
}
method2.invoke(instance, invoke);
}
}
return (T) instance;
}
servlet中使用
User user = WebUtils.fillBean(request,User.class);
System.out.println(user);
注意
User中的屬性一定要跟jsp中的屬性一致。
原理
private void datatoentity(HttpServletRequest request) {
try {
//約定:表單的每個控件name屬性值 和 需要封裝的對象的屬性名稱保持一致??!
User user = new User();
//獲取所有參數(shù)
Map<String,String[]> map = request.getParameterMap();
for(Entry<String,String[]> entry: map.entrySet()){
//參數(shù)名稱(相當(dāng)于對象的屬性名)
String paramName = entry.getKey();
//參數(shù)值
String[] paramValue = entry.getValue();
//得到對象的屬性(Field)
//得到類對象
Class clazz = user.getClass();
//獲取類的某個屬性(Field)
Field field = clazz.getDeclaredField(paramName);
//暴力反射
field.setAccessible(true);
//給屬性賦值
//如果參數(shù)值有多個,則存入數(shù)組,否則存入數(shù)組的第一個元素
if(paramValue.length>1){
//賦值
field.set(user, paramValue);
}else{
field.set(user, paramValue[0]);
}
}
System.out.println(user);
}catch (Exception e) {
e.printStackTrace();
}
}
路徑問題
瀏覽器行為 指向主機的根目錄 tomcat/webapps
服務(wù)器行為 指向當(dāng)前web應(yīng)用的根目錄 項目名稱servlettest
服務(wù)端 項目根目錄
服務(wù)器行為
getServletContext().getRealPath("/");
服務(wù)器行為
getServletContext().getResourceAsStream("/");
服務(wù)器行為
req.getRequestDispatcher("/");
服務(wù)器行為 /是否開頭都一樣
<%@ page errorPage="/" %>
服務(wù)器行為 /是否開頭都一樣
<%@ include file="/" %>
瀏覽器 tomcat/webapps目錄
瀏覽器行為
resp.sendRedirect("/");
瀏覽器行為
/onetest/one 絕對路徑,tomcat/webapps
one 相對路徑,默認(rèn)是項目根目錄
<form action="/">
瀏覽器行為
/onetest/two 絕對路徑,tomcat/webapps
two 相對路徑,默認(rèn)是項目根目錄
<a href="/" />
瀏覽器行為
one.css 相對路徑
/onetest/one.css 絕對路徑
<link rel="stylesheet" type="text/css" href="/" />
瀏覽器行為
/onetest/info.js 絕對路徑
info.js 相對路徑,可以這樣寫,根目錄就是項目 目錄
<script type="text/javascript" src="/"></script>
瀏覽器行為-超鏈接
response.getWriter().write("<a href='/項目名/路徑'>超鏈接</a>");
瀏覽器行為-表單
response.getWriter().write("<form action='/項目名/路徑'></form>");
會話管理
概述
好比是一次通話。從打開瀏覽器,訪問多次服務(wù)器資源,關(guān)閉瀏覽器,這個過程就一次會話。
是客戶與Web服務(wù)器間一連串的交互過程。
會話管理就是解決多個請求數(shù)據(jù)共享的問題。
例如:多個用戶使用瀏覽器與服務(wù)器進(jìn)行會話的過程中,服務(wù)器怎樣會每個用戶保存這些數(shù)據(jù)。
兩種技術(shù)
Cookie技術(shù):客戶端技術(shù),數(shù)據(jù)是保存在瀏覽器的緩存中
定義:Cookie是一些數(shù)據(jù),從Servlet發(fā)給瀏覽器,在瀏覽器中保存,然后通過瀏覽器發(fā)回給服務(wù)器。
屬性:
name : cookie的名稱
value : cookie的數(shù)據(jù)
comment : 注釋
path : 保存的路徑
domain : 保存的主機
maxAge : cookie存活的時間
負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
正數(shù):Cookie存活在緩存文件中,只有刪除緩存文件Cookie才會丟失。
零 :立即過期,用于刪除同名的Cookie
version : cookie的版本
servlet方法
添加 addCookie()
接收 getCookies()
限制
1)類型必須是字符串
2)cookie的長度不能超過4k,一個網(wǎng)站1次只能最多發(fā)20個,所有網(wǎng)站一共發(fā)300個
3)數(shù)據(jù)保存瀏覽器,安全性差
優(yōu)點
利用瀏覽器資源,減輕服務(wù)器壓力
HttpSession技術(shù):服務(wù)器端技術(shù),數(shù)據(jù)時保存在服務(wù)器內(nèi)存中的
是一個域?qū)ο? 獲取方式
HttpSession session = request.getSession();
常用方法
setAttribute(key,value)
getAttribute(key)
特點
增加服務(wù)器壓力
任意數(shù)據(jù)類型
大小沒有限制
相對安全
Cookie
創(chuàng)建Cookie
Cookie cookie = new Cookie("name","shuaige");
/*
* 設(shè)置Cookie存活時間
* 負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
* 正數(shù):Cookie存活在緩存文件中,只有刪除緩存文件Cookie才會丟失。
* 零 :立即過期,用于刪除同名的Cookie
* */
cookie.setMaxAge(Integer.MAX_VALUE);
//默認(rèn)路徑 /項目名
cookie.setPath("/servlet/servlettest");
//發(fā)送給瀏覽器
response.addCookie(cookie);
每次瀏覽器請求會默認(rèn)帶著Cookie
//接收Cookie
//注意什么情況可以取出Cookie發(fā)送到服務(wù)器? 獲取Cookie路徑.startWith(Cookie的保存路徑)=true的情況下可以獲取。
//注意:如果把Cookie的保存路徑設(shè)置為當(dāng)前Web應(yīng)用的根目錄,那么在當(dāng)前web應(yīng)用下所有訪問資源時都能取出該Cookie
Cookie[] cookies = request.getCookies();
for(int i = 0;i<cookies.length;i++){
Cookie cookie1 = cookies[i];
System.out.println(cookie1);
}
獲取用戶上次訪問的時間
用Cookie來記錄瀏覽過的商品
domain表示的是cookie所在的域,默認(rèn)為請求的地址
同域訪問
http://bbs.shuaige.com/onttest/one的默認(rèn)域名是bbs.shuaige.com
跨域訪問
http://bbs.shuaige.com/onttest/one
http://aas.shuaige.com/onetest/one
設(shè)置domain為.shuaige.com就可以跨域訪問了。
本域設(shè)置不可以訪問的
例如http://bbs.shuaige.com/onttest/one設(shè)置不可以訪問,并且http://aas.shuaige.com/onetest/one可以訪問的
設(shè)置domain為aas.shuaige.com就可以跨域訪問了。
path是cookie所在目錄
瀏覽器會將domain和path都相同的cookie保存在一個文件里,cookie間用*隔開
HttpSession
存值
//獲取session
HttpSession session = request.getSession();
//把數(shù)據(jù)存到session中
session.setAttribute("name", "shuaige");
取值
//獲取session
HttpSession session = request.getSession();
//把數(shù)據(jù)從session中取出
String name = (String)session.getAttribute("name");
System.out.println(name);
request.getSession()方法
1.查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
有:返回對應(yīng)的對象
沒有:創(chuàng)建一個新的對象返回
2.HttpSession對象會設(shè)置一個對應(yīng)瀏覽器的JSESSINOID,通過請求頭(set-cookie)實現(xiàn)。
HttpSession session = request.getSession();
String sid = session.getId();
服務(wù)器也是根據(jù)這個JSESSINOID來取出對應(yīng)的session
3.注意:
request.getSession(true)/request.getSession()
查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
有:返回對應(yīng)的對象
沒有:創(chuàng)建一個新的對象返回
request.getSession(false)
查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
有:返回對應(yīng)的對象
沒有:返回null
原理
HttpSession對象會設(shè)置一個對應(yīng)瀏覽器的JSESSINOID,通過請求頭(set-cookie)實現(xiàn)。
HttpSession session = request.getSession();
String sid = session.getId();
服務(wù)器也是根據(jù)這個JSESSINOID來取出對應(yīng)的session
購物車
會員登錄
HttpSession鈍化與激活
正常關(guān)閉服務(wù)
HttpSession對象過久沒有訪問
第三方控件-上傳
概述
由非軟件提供商提供的功能組件
commons-fileupload文件上傳組件
Apache提供的實現(xiàn)文件上傳的組件
免費的、開源的
commons-fileupload API
FileItemFactory接口
用于構(gòu)建FileItem實例
DiskFileItemFactory類
是FileItemFactory接口實現(xiàn)類
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload類
組件的核心類
封裝表單元素并以集合方式返回
ServletFileUpload(FileItemFactory fileitemfactory)
boolean isMultipartContent (HttpServletRequest request)
靜態(tài)方法。用于判斷請求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型。是返回true,否返回false
List parseRequest(HttpServletRequest request)
將請求數(shù)據(jù)中的每一個字段,單獨封裝成FileItem對象,并以List方式返回
FileItem類
封裝表單元素的數(shù)據(jù)
具有對表單內(nèi)容處理的方法
常用方法
String getFieldName() 返回表單字段元素的name屬性值
boolean isFormField() 判斷FileItem封裝的數(shù)據(jù)是屬于普通表單字段,或者是文件表單字段。普通表單字段:true,文件表單字段:false。
String getName() 返回上傳文件字段中的文件名,文件名通常是不含路徑信息的,取決于瀏覽器實現(xiàn)
void write(File file) 將FileItem對象中的內(nèi)容保存到指定文件中
String getString() 按照默認(rèn)編碼格式返回字符串
String getString(String encoding) 按照指定編碼格式將內(nèi)容轉(zhuǎn)換成字符串返回
使用步驟
1.獲取commons-fileupload組件
commons-fileupload-版本號.jar
commons-io-版本號.jar
2.導(dǎo)入jar包
3.設(shè)置表單提交屬性
<form name="form1" method="post" enctype="multipart/form-data" />
4.實現(xiàn)Servlet中的上傳
4.1判斷請求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型ServletFileUpload.isMultipartContent(req)
4.2創(chuàng)建FileItemFactory實例new DiskFileItemFactory()
4.3創(chuàng)建ServletFileUpload實例new ServletFileUpload(factory)
4.4解析request請求,獲取表單元素對應(yīng)的FileItem集合upload.parseRequest(req)
4.5循環(huán)遍歷獲取數(shù)據(jù)
4.6判斷元素類型,true-普通表單元素,false-文件元素item.isFormField()
4.7如果是文件元素
4.7.1獲取文件名稱item.getName()
4.7.2如果有名稱亂碼就處理亂碼new String(name.getBytes("GBK"),"UTF-8")
4.7.3寫出到指定位置item.write(file)
代碼
<form action="one" enctype="multipart/form-data" method="post">
<input name="username" type="text"/>
<input name="file" type="file" />
<input type="submit" value="提交">
</form>
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if(isMultipart){
//創(chuàng)建FileItemFactory實例
//參數(shù)一:代表緩存大小。假如設(shè)置的大小是1M,如果上傳的文件不超過1M,那么不用緩存,如果超過1M,就使用緩存
//參數(shù)二:代表緩存的目錄。
//DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
FileItemFactory factory = new DiskFileItemFactory();
//創(chuàng)建ServletFileUpload實例
ServletFileUpload upload = new ServletFileUpload(factory);
try {
//限制文件大?。ㄏ拗茊蝹€文件不超過200KB,總文件大小不超過500KB)
//upload.setFileSizeMax(200*1024);//限制單個文件不超過200KB
//upload.setSizeMax(500*1024);//總文件大小不超過500KB
List<FileItem> list = upload.parseRequest(req);
for(FileItem item : list){
if(!item.isFormField()){
//限制文件類型(只能上傳圖片文件) mime類型: text/plain image/*
String contentType = item.getContentType();
if(!contentType.matches("image/[a-zA-Z]+")){
request.setAttribute("msg", "只允許上傳圖片格式的文件!");
request.getRequestDispatcher("/upload4.jsp").forward(request, response);
return;
}
String name = item.getName();
name = new String(name.getBytes("GBK"),"UTF-8");
String savePath = "f:\\"+name;
File file = new File(savePath);
item.write(file);
}else{
System.out.println("表單元素:"+item.getFieldName()+"-"+item.getString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
分頁
優(yōu)勢
數(shù)據(jù)能夠按照指定格式顯示,布局清晰
不受信息數(shù)量的限制
不足
當(dāng)數(shù)據(jù)量較多,頁面顯示不完全時,需要用戶拖動頁面才能瀏覽更多信息
實現(xiàn)
Dao中
1.獲取表中數(shù)據(jù)總條數(shù) int getCount();
2.獲取指定顯示的條目 List<User> getUser(int start,int count);
Service中
1.每頁顯示條目個數(shù)
int pagenum = 6;
2.計算頁數(shù)int getTotalPageCount()
public int getTotalPageCount(){
int count = getCount();
int num = count / pagenum;
if(count%pagenum != 0){
num = num+1;
}
return num;
}
3.獲取指定顯示的條目
public List<User> getUsers(int pageIndex){
int start = (pageIndex-1)*pagenum;
List<User> user = userDao.getUser(start, pagenum);
return user;
}
Controller中
1.獲取頁面總條目
String totalPageCountStr = req.getParameter("totalPageCount");
int totalPageCount = 0;
if(totalPageCountStr != null){
totalPageCount = Integer.valueOf(totalPageCountStr);
}else{
totalPageCount = service.getTotalPageCount();
}
2.獲取當(dāng)前顯示多少頁
String pageIndexStr = req.getParameter("pageIndex");
int pageIndex = 1;
if(pageIndexStr != null){
pageIndex = Integer.valueOf(pageIndexStr);
}
3.獲取需要顯示的數(shù)據(jù)
List<User> users = service.getUsers(pageIndex);
4.設(shè)置返回參數(shù)
req.setAttribute("pageIndex", pageIndex);
req.setAttribute("totalPageCount", totalPageCount);
req.setAttribute("users",users);
jsp中
顯示數(shù)據(jù)
<table border="1">
<tr>
<th>id</th>
<th>name</th>
<th>age</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id }</td>
<td>${user.name }</td>
<td>${user.age }</td>
</tr>
</c:forEach>
</table>
顯示所有頁數(shù)的鏈接
<%
int totalPageCount = (Integer)request.getAttribute("totalPageCount");
int pageIndex = (Integer)request.getAttribute("pageIndex");
for(int i = 1;i<=totalPageCount;i++){
StringBuffer sb = new StringBuffer();
if(i == pageIndex){
sb.append("<a style='padding: 5px;'>");
}else{
sb.append("<a href='one?pageIndex=");
sb.append(i);
sb.append("&totalPageCount=");
sb.append(totalPageCount);
sb.append("' style='padding: 5px;'>");
}
sb.append(i);
sb.append("</a>");
out.write(sb.toString());
}
%>
Servlet注解配置
@WebServlet("/login")
手動文件上傳
//1)讀取請求正文
InputStream in = request.getInputStream();
//2)轉(zhuǎn)換為字符讀取流
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//3)第一行:讀取文件的分割符
String fileTag = br.readLine();
//4)第二行:讀取文件名稱
String line = br.readLine();
String fileName = line.substring( line.lastIndexOf("filename=\"")+10 , line.length()-1);
//跳過兩行
br.readLine();
br.readLine();
//5)讀取文件內(nèi)容
String str = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\targetFiles\\"+fileName));
//不斷讀取
while( (str=br.readLine())!=null ){
//忽略文件的分割符
if( (fileTag+"--").equals(str)){
break;
}
bw.write(str);//寫出一行
bw.newLine();//換行符
}
bw.close();
br.close();