Servlet介紹
概述
Servlet是運(yùn)行在服務(wù)器端的Java應(yīng)用程序
servlet程序開發(fā)動(dòng)態(tài)資源的技術(shù)
Servlet(Server Applet)是Java Servlet的簡稱同蜻,稱為小服務(wù)程序或服務(wù)連接器囚痴,
用Java編寫的服務(wù)器端程序,主要功能在于交互式地瀏覽和修改數(shù)據(jù)矾踱,生成動(dòng)態(tài)Web內(nèi)容。
作用:
用于接收和處理http請(qǐng)求(接收和響應(yīng)請(qǐng)求)
最核心的方法
void service(ServletRequest req,ServletResponse res)
ServletRequest req 代表請(qǐng)求對(duì)象炼吴,包含請(qǐng)求的所有內(nèi)容俄讹,用于獲取請(qǐng)求數(shù)據(jù)
ServletResponse res 代表響應(yīng)對(duì)象篮洁,包含響應(yīng)的所有內(nèi)容,用于修改響應(yīng)數(shù)據(jù)
Servlet開發(fā)步驟
1)java類删掀,繼承HttpServlet類
覆蓋doGet和doPost方法
2)在web應(yīng)用web.xml中配置servlet
3)請(qǐng)求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ǔ)上擴(kuò)展了Http協(xié)議的Servlet
//會(huì)先調(diào)用service方法,然后根據(jù)請(qǐng)求方式來進(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披泪,相對(duì)于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 {
//這個(gè)super一定不要?jiǎng)h掉
super.init(config);
//通過ServletConfig對(duì)象讀取初始化參數(shù)
String initParameter = config.getInitParameter("initParam");
System.out.println(initParameter);
//獲得所有參數(shù)的key
Enumeration<String> enumeration = config.getInitParameterNames();
}
有參的init 與 無參init
有參init:生命周期方法纤子,必定會(huì)被服務(wù)器調(diào)用。(內(nèi)部默認(rèn)會(huì)調(diào)用無參的init方法)
無參init:提供給開發(fā)者進(jìn)行初始化工作的方法付呕。
Servlet生命周期
實(shí)例化 - Servlet 容器創(chuàng)建 Servlet 的實(shí)例
初始化 - 容器調(diào)用 init() 方法
請(qǐng)求處理 - 如果請(qǐng)求 Servlet计福,則容器調(diào)用 service() 方法
服務(wù)終止/重新部署 - 銷毀實(shí)例之前調(diào)用 destroy() 方法,通過stop server看
Servlet線程安全問題
Servlet 在服務(wù)器中是單實(shí)例多線程的徽职。
每次都會(huì)在Service方法中新建一個(gè)子線程來處理請(qǐng)求:new ThreadServlet()
引起并發(fā)問題的原因:在Servlet中使用了成員變量(多個(gè)線程共享的數(shù)據(jù))象颖。
測試:
可以通過在Servlet中輸出一個(gè)count值,然后線程睡眠姆钉,最后count++说订。
用兩個(gè)瀏覽器同時(shí)去訪問。會(huì)發(fā)現(xiàn)最后輸出的結(jié)果是一樣的潮瓶。
解決多并發(fā)陶冷,用同步
在doGet方法中
synchronized (OneServlet.class) {
//業(yè)務(wù)代碼
}
建議:
盡量不要在Servlet中使用成員變量
如果使用了成員變量,那么就需要使用synchronized進(jìn)行同步代碼毯辅,而且盡量縮小同步的范圍
Servlet的一些細(xì)節(jié)
改變Servlet的創(chuàng)建時(shí)機(jī)
<servlet>
<servlet-name>one</servlet-name>
<servlet-class>com.shuai.action.ThreeServlet</servlet-class>
<!-- 在項(xiàng)目部署啟動(dòng)的時(shí)候埂伦,默認(rèn)創(chuàng)建Servlet,數(shù)值越大優(yōu)先級(jí)越低 -->
<load-on-startup>1</load-on-startup>
</servlet>
路徑映射規(guī)則
url-pattern 頁面訪問
精確映射 /one /one
/test/one /test/one
模糊映射 /* /任意路徑
/test/* /test/任意路徑
*.后綴 任意路徑.后綴
注意:
url-pattern要么以/或者*開頭
當(dāng)前有多個(gè)url-pattern思恐,優(yōu)先級(jí)問題
后綴名結(jié)尾的url-pattern優(yōu)先級(jí)最低
哪個(gè)更加精確哪個(gè)優(yōu)先
ServletConfig對(duì)象
概述
Servlet配置對(duì)象
作用
用于讀取servlet參數(shù)
如何得到ServletConfig對(duì)象
通過有參的init方法獲得
通過getServletConfig()獲得
ServletContext對(duì)象
概述
ServletContext是servlet的上下文對(duì)象沾谜。
代表當(dāng)前web應(yīng)用。
一個(gè)web有且只有一個(gè)ServletContext對(duì)象胀莹。
獲取ServletContext對(duì)象
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();
//獲取一個(gè)文件的絕對(duì)路徑 - 獲取的項(xiàng)目根目錄
//要以/開頭
String realPath = servletContext.getRealPath("/");
System.out.println(realPath);
//讀取一個(gè)文件基跑,并且返回一個(gè)文件流
InputStream inputStream = servletContext.getResourceAsStream("/路徑");
HttpServletResponse對(duì)象
response對(duì)象
表示響應(yīng)對(duì)象,包含所有的響應(yīng)數(shù)據(jù)描焰。使用response對(duì)象可以修改響應(yīng)數(shù)據(jù)媳否。
響應(yīng)格式
響應(yīng)行
http版本
狀態(tài)碼 setStatus(sc)方法
描述
響應(yīng)頭
鍵值對(duì)
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ù)器- 這個(gè)代碼可以省略
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ù)器之間請(qǐng)求頭和響應(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();
輸出隨機(jī)驗(yàn)證碼(防止惡意注冊(cè)和登錄)
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è)置隨機(jī)干擾線
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);
//隨機(jī)色
graphics.setColor(getRanColor());
graphics.drawLine(x1, y1, x2, y2);
}
//把這個(gè)圖片寫出給瀏覽器
ServletOutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "gif", outputStream);
}
//獲取隨機(jī)顏色
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ā)出兩次請(qǐng)求
地址欄會(huì)發(fā)生變化
可以重定向任何資源(包括應(yīng)用外的資源)
不可以通過request來共享數(shù)據(jù)
代碼
response.sendRedirect("/info.jsp");
HttpServletRequest對(duì)象
概述
表示請(qǐng)求對(duì)象,包含所有的請(qǐng)求數(shù)據(jù)室抽。使用request獲取請(qǐng)求的數(shù)據(jù)搪哪。
請(qǐng)求格式
請(qǐng)求行
請(qǐng)求方式 request.getMethod()
請(qǐng)求資源 request.getRequestURL() / request.getRequestURI()
http版本 request.getProtocol()
獲得get請(qǐng)求的參數(shù) request.getQueryString()
請(qǐng)求頭
獲得一個(gè)請(qǐng)求頭 getHeader(key)
獲得整形的請(qǐng)求頭 getIntHeader(key)
獲得日期類型的請(qǐng)求頭 getDateHeader(key)
空行
正文
獲得正文 getInputStream()
防盜鏈
String referer = request.getHeader("referer");
if(referer == null || !referer.contains("/servlettest")){
//非法連接
return;
}
獲取表單數(shù)據(jù)
get : getQueryString()
post : getInputStream()
通用方式
獲取某個(gè)參數(shù) getParameter("")
獲取某個(gè)參數(shù)的集合 getParameterValues("") 例如:checkbox
獲取所有的參數(shù)名 getParameterNames()
獲取所有的參數(shù) getParameterMap()
亂碼問題
if("post".equalsIgnoreCase(request.getMethod())){
//只能解決post提交的參數(shù),不能解決get提交的參數(shù)坪圾,因?yàn)檫@個(gè)方法只能設(shè)置請(qǐng)求正文的內(nèi)容
request.setCharacterEncoding("UTF-8");
}
String name = request.getParameter("name");//默認(rèn)是iso-8859-1
if("get".equalsIgnoreCase(request.getMethod())){
//get請(qǐng)求的參數(shù)需要手動(dòng)解碼
name = new String(name.getBytes("iso-8859-1"),"UTF-8");
}
轉(zhuǎn)發(fā)
發(fā)出一次請(qǐng)求
地址欄不會(huì)發(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>
后臺(tái)工具類
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 {
//約定:表單的每個(gè)控件name屬性值 和 需要封裝的對(duì)象的屬性名稱保持一致!兽泄!
User user = new User();
//獲取所有參數(shù)
Map<String,String[]> map = request.getParameterMap();
for(Entry<String,String[]> entry: map.entrySet()){
//參數(shù)名稱(相當(dāng)于對(duì)象的屬性名)
String paramName = entry.getKey();
//參數(shù)值
String[] paramValue = entry.getValue();
//得到對(duì)象的屬性(Field)
//得到類對(duì)象
Class clazz = user.getClass();
//獲取類的某個(gè)屬性(Field)
Field field = clazz.getDeclaredField(paramName);
//暴力反射
field.setAccessible(true);
//給屬性賦值
//如果參數(shù)值有多個(gè)漓概,則存入數(shù)組,否則存入數(shù)組的第一個(gè)元素
if(paramValue.length>1){
//賦值
field.set(user, paramValue);
}else{
field.set(user, paramValue[0]);
}
}
System.out.println(user);
}catch (Exception e) {
e.printStackTrace();
}
}
路徑問題
瀏覽器行為 指向主機(jī)的根目錄 tomcat/webapps
服務(wù)器行為 指向當(dāng)前web應(yīng)用的根目錄 項(xiàng)目名稱servlettest
服務(wù)端 項(xiàng)目根目錄
服務(wù)器行為
getServletContext().getRealPath("/");
服務(wù)器行為
getServletContext().getResourceAsStream("/");
服務(wù)器行為
req.getRequestDispatcher("/");
服務(wù)器行為 /是否開頭都一樣
<%@ page errorPage="/" %>
服務(wù)器行為 /是否開頭都一樣
<%@ include file="/" %>
瀏覽器 tomcat/webapps目錄
瀏覽器行為
resp.sendRedirect("/");
瀏覽器行為
/onetest/one 絕對(duì)路徑病梢,tomcat/webapps
one 相對(duì)路徑胃珍,默認(rèn)是項(xiàng)目根目錄
<form action="/">
瀏覽器行為
/onetest/two 絕對(duì)路徑,tomcat/webapps
two 相對(duì)路徑蜓陌,默認(rèn)是項(xiàng)目根目錄
<a href="/" />
瀏覽器行為
one.css 相對(duì)路徑
/onetest/one.css 絕對(duì)路徑
<link rel="stylesheet" type="text/css" href="/" />
瀏覽器行為
/onetest/info.js 絕對(duì)路徑
info.js 相對(duì)路徑觅彰,可以這樣寫犬金,根目錄就是項(xiàng)目 目錄
<script type="text/javascript" src="/"></script>
瀏覽器行為-超鏈接
response.getWriter().write("<a href='/項(xiàng)目名/路徑'>超鏈接</a>");
瀏覽器行為-表單
response.getWriter().write("<form action='/項(xiàng)目名/路徑'></form>");
會(huì)話管理
概述
好比是一次通話絮短。從打開瀏覽器,訪問多次服務(wù)器資源辆童,關(guān)閉瀏覽器隧期,這個(gè)過程就一次會(huì)話飒责。
是客戶與Web服務(wù)器間一連串的交互過程。
會(huì)話管理就是解決多個(gè)請(qǐng)求數(shù)據(jù)共享的問題仆潮。
例如:多個(gè)用戶使用瀏覽器與服務(wù)器進(jìn)行會(huì)話的過程中宏蛉,服務(wù)器怎樣會(huì)每個(gè)用戶保存這些數(shù)據(jù)。
兩種技術(shù)
Cookie技術(shù):客戶端技術(shù)性置,數(shù)據(jù)是保存在瀏覽器的緩存中
定義:Cookie是一些數(shù)據(jù)拾并,從Servlet發(fā)給瀏覽器,在瀏覽器中保存鹏浅,然后通過瀏覽器發(fā)回給服務(wù)器辟灰。
屬性:
name : cookie的名稱
value : cookie的數(shù)據(jù)
comment : 注釋
path : 保存的路徑
domain : 保存的主機(jī)
maxAge : cookie存活的時(shí)間
負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
正數(shù):Cookie存活在緩存文件中篡石,只有刪除緩存文件Cookie才會(huì)丟失。
零 :立即過期西采,用于刪除同名的Cookie
version : cookie的版本
servlet方法
添加 addCookie()
接收 getCookies()
限制
1)類型必須是字符串
2)cookie的長度不能超過4k凰萨,一個(gè)網(wǎng)站1次只能最多發(fā)20個(gè),所有網(wǎng)站一共發(fā)300個(gè)
3)數(shù)據(jù)保存瀏覽器,安全性差
優(yōu)點(diǎn)
利用瀏覽器資源胖眷,減輕服務(wù)器壓力
HttpSession技術(shù):服務(wù)器端技術(shù)武通,數(shù)據(jù)時(shí)保存在服務(wù)器內(nèi)存中的
是一個(gè)域?qū)ο? 獲取方式
HttpSession session = request.getSession();
常用方法
setAttribute(key,value)
getAttribute(key)
特點(diǎn)
增加服務(wù)器壓力
任意數(shù)據(jù)類型
大小沒有限制
相對(duì)安全
Cookie
創(chuàng)建Cookie
Cookie cookie = new Cookie("name","shuaige");
/*
* 設(shè)置Cookie存活時(shí)間
* 負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
* 正數(shù):Cookie存活在緩存文件中珊搀,只有刪除緩存文件Cookie才會(huì)丟失冶忱。
* 零 :立即過期,用于刪除同名的Cookie
* */
cookie.setMaxAge(Integer.MAX_VALUE);
//默認(rèn)路徑 /項(xiàng)目名
cookie.setPath("/servlet/servlettest");
//發(fā)送給瀏覽器
response.addCookie(cookie);
每次瀏覽器請(qǐng)求會(huì)默認(rèn)帶著Cookie
//接收Cookie
//注意什么情況可以取出Cookie發(fā)送到服務(wù)器境析? 獲取Cookie路徑.startWith(Cookie的保存路徑)=true的情況下可以獲取囚枪。
//注意:如果把Cookie的保存路徑設(shè)置為當(dāng)前Web應(yīng)用的根目錄,那么在當(dāng)前web應(yīng)用下所有訪問資源時(shí)都能取出該Cookie
Cookie[] cookies = request.getCookies();
for(int i = 0;i<cookies.length;i++){
Cookie cookie1 = cookies[i];
System.out.println(cookie1);
}
獲取用戶上次訪問的時(shí)間
用Cookie來記錄瀏覽過的商品
domain表示的是cookie所在的域劳淆,默認(rèn)為請(qǐng)求的地址
同域訪問
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所在目錄
瀏覽器會(huì)將domain和path都相同的cookie保存在一個(gè)文件里括勺,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ù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
有:返回對(duì)應(yīng)的對(duì)象
沒有:創(chuàng)建一個(gè)新的對(duì)象返回
2.HttpSession對(duì)象會(huì)設(shè)置一個(gè)對(duì)應(yīng)瀏覽器的JSESSINOID,通過請(qǐng)求頭(set-cookie)實(shí)現(xiàn)。
HttpSession session = request.getSession();
String sid = session.getId();
服務(wù)器也是根據(jù)這個(gè)JSESSINOID來取出對(duì)應(yīng)的session
3.注意:
request.getSession(true)/request.getSession()
查詢服務(wù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
有:返回對(duì)應(yīng)的對(duì)象
沒有:創(chuàng)建一個(gè)新的對(duì)象返回
request.getSession(false)
查詢服務(wù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
有:返回對(duì)應(yīng)的對(duì)象
沒有:返回null
原理
HttpSession對(duì)象會(huì)設(shè)置一個(gè)對(duì)應(yīng)瀏覽器的JSESSINOID,通過請(qǐng)求頭(set-cookie)實(shí)現(xiàn)曲掰。
HttpSession session = request.getSession();
String sid = session.getId();
服務(wù)器也是根據(jù)這個(gè)JSESSINOID來取出對(duì)應(yīng)的session
購物車
會(huì)員登錄
HttpSession鈍化與激活
正常關(guān)閉服務(wù)
HttpSession對(duì)象過久沒有訪問
第三方控件-上傳
概述
由非軟件提供商提供的功能組件
commons-fileupload文件上傳組件
Apache提供的實(shí)現(xiàn)文件上傳的組件
免費(fèi)的疾捍、開源的
commons-fileupload API
FileItemFactory接口
用于構(gòu)建FileItem實(shí)例
DiskFileItemFactory類
是FileItemFactory接口實(shí)現(xiàn)類
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload類
組件的核心類
封裝表單元素并以集合方式返回
ServletFileUpload(FileItemFactory fileitemfactory)
boolean isMultipartContent (HttpServletRequest request)
靜態(tài)方法。用于判斷請(qǐng)求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型栏妖。是返回true乱豆,否返回false
List parseRequest(HttpServletRequest request)
將請(qǐng)求數(shù)據(jù)中的每一個(gè)字段,單獨(dú)封裝成FileItem對(duì)象底哥,并以List方式返回
FileItem類
封裝表單元素的數(shù)據(jù)
具有對(duì)表單內(nèi)容處理的方法
常用方法
String getFieldName() 返回表單字段元素的name屬性值
boolean isFormField() 判斷FileItem封裝的數(shù)據(jù)是屬于普通表單字段咙鞍,或者是文件表單字段。普通表單字段:true趾徽,文件表單字段:false续滋。
String getName() 返回上傳文件字段中的文件名,文件名通常是不含路徑信息的孵奶,取決于瀏覽器實(shí)現(xiàn)
void write(File file) 將FileItem對(duì)象中的內(nèi)容保存到指定文件中
String getString() 按照默認(rèn)編碼格式返回字符串
String getString(String encoding) 按照指定編碼格式將內(nèi)容轉(zhuǎn)換成字符串返回
使用步驟
1.獲取commons-fileupload組件
commons-fileupload-版本號(hào).jar
commons-io-版本號(hào).jar
2.導(dǎo)入jar包
3.設(shè)置表單提交屬性
<form name="form1" method="post" enctype="multipart/form-data" />
4.實(shí)現(xiàn)Servlet中的上傳
4.1判斷請(qǐng)求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型ServletFileUpload.isMultipartContent(req)
4.2創(chuàng)建FileItemFactory實(shí)例new DiskFileItemFactory()
4.3創(chuàng)建ServletFileUpload實(shí)例new ServletFileUpload(factory)
4.4解析request請(qǐng)求,獲取表單元素對(duì)應(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ù)一:代表緩存大小疲酌。假如設(shè)置的大小是1M,如果上傳的文件不超過1M了袁,那么不用緩存朗恳,如果超過1M,就使用緩存
//參數(shù)二:代表緩存的目錄载绿。
//DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
FileItemFactory factory = new DiskFileItemFactory();
//創(chuàng)建ServletFileUpload實(shí)例
ServletFileUpload upload = new ServletFileUpload(factory);
try {
//限制文件大兄嘟搿(限制單個(gè)文件不超過200KB,總文件大小不超過500KB)
//upload.setFileSizeMax(200*1024);//限制單個(gè)文件不超過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ù)量較多怀浆,頁面顯示不完全時(shí)谊囚,需要用戶拖動(dòng)頁面才能瀏覽更多信息
實(shí)現(xiàn)
Dao中
1.獲取表中數(shù)據(jù)總條數(shù) int getCount();
2.獲取指定顯示的條目 List<User> getUser(int start,int count);
Service中
1.每頁顯示條目個(gè)數(shù)
int pagenum = 6;
2.計(jì)算頁數(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")
手動(dòng)文件上傳
//1)讀取請(qǐng)求正文
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();