本篇學(xué)習(xí)筆記總結(jié)自bilibiliup主【狂神說Java】系列視頻:【狂神說Java】JavaWeb入門到實戰(zhàn)
視頻作者公眾號:狂神說
Web開發(fā):
靜態(tài)Web
動態(tài)web
淘寶,幾乎所有的網(wǎng)站
每個人在不同的時間不同的地點看到的信息各不相同
常用的技術(shù)棧:Servlet/JSP, ASP, PHp
在Java中,動態(tài)web資源開發(fā)的技術(shù)棧叫JavaWeb
Web應(yīng)用程序:可以提供給瀏覽器訪問的程序
web應(yīng)用程序編寫完畢后,如果想提供給外界訪問,需要一個服務(wù)器進(jìn)行統(tǒng)一管理:
Web頁面展示的效果因人而異
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-od9xlHbs-1587810422900)(JavaWeb.assets/截屏2020-04-18 上午12.55.05.png)]
缺點:
優(yōu)點:
實現(xiàn)web手段:
ASP
PHP
JSP/servlet:
B/S:瀏覽器和服務(wù)器
C/S:客戶端和服務(wù)器
服務(wù)器是一種被動的操作,用來處理用戶的一些請求和用戶的一些相應(yīng)信息
IIS:windows自帶
Tomcat:技術(shù)先進(jìn)性能穩(wěn)定的免費Web服務(wù)器,實際上運行的JSP頁面以及Servlet,具有處理HTML頁面的功能,另外它還是一個Serlvet和JSP容器,獨立的Servlet容器是Tomcat的基本模式
bin
:啟動、關(guān)閉的腳本文件conf
:配置lib
:依賴的jar包logs
:日志文件,輸出webapps
:存放網(wǎng)站Server.xml
可以更改服務(wù)器端口
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
常用的端口號:
可以配置主機(jī)名稱:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"></Host>
<Host name = "localhost">
服務(wù)器在訪問域名時,會去查看host文件的映射關(guān)系,之后再去DNS服務(wù)器那里進(jìn)行轉(zhuǎn)換,比如這里的localhost換一個其他域名,需要在系統(tǒng)的host文件夾更改映射關(guān)系。
面試題:網(wǎng)站是如何進(jìn)行訪問的?
將自己的網(wǎng)站,放在服務(wù)器(tomcat)指定的web應(yīng)用文件夾下(webapps),打開localhost:8080/項目名
就可以訪問了
網(wǎng)站應(yīng)該有的結(jié)構(gòu)
--webapps /* Tomcat服務(wù)器目錄*/ -ROOT -NeilStudy: /*網(wǎng)站的目錄名*/ -index.html /*默認(rèn)的首頁*/ -WEB-INF -classes /*Java程序*/ -lib /*web應(yīng)用所依賴的jar包*/ -web.xml. /*網(wǎng)站配置文件*/ - static /*靜態(tài)文件*/ -css -style.css -js -img
http(超文本傳輸協(xié)議)是一個簡單的請求-響應(yīng)協(xié)議,它通常運行在TCP之上。它指定了客戶端可能發(fā)送給服務(wù)器什么樣的消息以及得到什么樣的響應(yīng)。
客戶端–發(fā)送請求(request)—服務(wù)器
百度:
Request URL: https://www.baidu.com/Request Method: GETStatus Code : 200 狀態(tài)碼Remote Address:14.215.177.39:443
服務(wù)器—響應(yīng)— 客戶端
百度
Cache-Control: private //緩存控制Connection: keep-alive //tcp長鏈接Content-Encoding: gzip //編碼Content-Type: text/html;charset=utf-8 //類型
為什么要學(xué)習(xí)這個技術(shù)
JavaWeb中需要使用大量的Jar包,需要手動去導(dǎo)入
需要一個工具自動導(dǎo)入Jar包
由此,maven誕生了!
Maven核心思想:約定大于配置
Maven會規(guī)定好如何去編寫Java代碼,必須按照規(guī)范
案例:
<mirrors> <mirror> <id>nexus-aliyun</id> <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf> <name>Nexus maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> </mirrors>
建立一個本地倉庫:localRepository
<localRepository>相對路徑,如.\apache-maven-3.6.3\maven-repo</localRepository>
啟動IDAR
創(chuàng)建一個Maven項目(可以選擇結(jié)構(gòu))
觀察倉庫結(jié)構(gòu)
創(chuàng)建java文件夾
標(biāo)記成為資源路徑(project structure 可以標(biāo)記資源)
標(biāo)準(zhǔn)的Maven項目都會有一個resources目錄來存放我們所有的資源配置文件,但是我們往往在項目中不僅僅會把所有的資源配置文件都放在resources中,同時我們也有可能放在項目中的其他位置,那么默認(rèn)的maven項目構(gòu)建編譯時就不會把我們其他目錄下的資源配置文件導(dǎo)出到target目錄中,就會導(dǎo)致我們的資源配置文件讀取失敗,從而導(dǎo)致我們的項目報錯出現(xiàn)異常,比如說尤其我們在使用MyBatis框架時,往往Mapper.xml配置文件都會放在dao包中和dao接口類放在一起的,那么執(zhí)行程序的時候,其中的xml配置文件就一定會讀取失敗,不會生成到maven的target目錄中,所以我們要在項目的pom.xml文件中進(jìn)行設(shè)置,并且我建議大家,每新建一個maven項目,就把該設(shè)置導(dǎo)入pom.xml文件中,以防不測?。?!
<build> ....... <resources> <resource> <directory>src/main/resources</directory> <excludes> <exclude>**/*.properties</exclude> <exclude>**/*.xml</exclude> </excludes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> ......</build>
把實現(xiàn)了Servlet接口的Java程序叫做,Servlet
Servelt在Sun公司有兩個默認(rèn)實現(xiàn)類:HttpServlet
新建一個普通的maven項目,刪掉src目錄
在pom里面添加Servlet和jsp的依賴
關(guān)于Maven父子工程的理解:
父項目中會有
<modules> <module>servlet-01</module> </modules>
子項目會有
<parent> <artifactId>javaWeb_servlet</artifactId> <groupId>com</groupId> <version>1.0-SHAPSHOT</version></parent>
父項目中的java子項目可以直接使用
Maven環(huán)境優(yōu)化
編寫一個Servlet程序
public class HelloServlet extends HttpServlet { //由于get或post只是請求實現(xiàn)的不同方式,可以互相調(diào)用 @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //響應(yīng)流 writer.print("Hello, Servlet"); }}
在web.xml編寫Servlet的映射
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.neil.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/servlet</url-pattern> </servlet-mapping>
一個Servlet可以指定一個或者多個映射路徑
<!--指定一個路徑--><servlet> <servlet-name>hello</servlet-name> <servlet-class>com.neil.servlet.HelloServlet</servlet-class></servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/servlet</url-pattern></servlet-mapping><servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/servlet01</url-pattern></servlet-mapping><!--增加后綴--><servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/servlet01/*</url-pattern></servlet-mapping><!--可以自定義后綴實現(xiàn)映射,*前面不能加/--><servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.neil</url-pattern></servlet-mapping>
Servlet優(yōu)先級為固有路徑最高,如果沒有就走默認(rèn)路徑
<!--自定義404 Servlet--><servlet> <servlet-name>error</servlet-name> <servlet-class>com.neil.servlet.ErrorServlet</servlet-class></servlet><servlet-mapping> <servlet-name>error</servlet-name> <url-pattern>/*</url-pattern></servlet-mapping>
Web容器在啟動的時候,它會為每個web程序都創(chuàng)建一個對應(yīng)的ServletContext對象,它代表了當(dāng)前的web應(yīng)用
應(yīng)用:
在一個Servlet中保存的數(shù)據(jù),可以在另外一個Servlet中拿到
放置:
public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext();//獲取上下文 String username = "Neil"; //數(shù)據(jù) servletContext.setAttribute("username",username); //將一個數(shù)數(shù)據(jù)保存在了servletContext中,用key value形式存儲 System.out.println("hello"); }}
讀?。?/p>
public class getServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String username = (String) this.getServletContext().getAttribute("username");//通過Key獲取Value resp.setContentType("text/html;charset=utf-8"); resp.getWriter().print("名字" + username); }}
web.xml
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.neil.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/neil</url-pattern> </servlet-mapping> <servlet> <servlet-name>getc</servlet-name> <servlet-class>com.neil.getServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>getc</servlet-name> <url-pattern>/getc</url-pattern> </servlet-mapping>
public class GetInitParameter extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); //通過key-value獲取配置在web.xml的初始化參數(shù) String url = servletContext.getInitParameter("url"); System.out.println(url); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().print("URL + " + url); }}
Web.xml
<!--配置初始化參數(shù)--><context-param> <param-name>url</param-name> <param-value>jdbc::mysql://localhost:3306/mybatis</param-value></context-param><servlet> <servlet-name>GetInitParam</servlet-name> <servlet-class>com.neil.GetInitParameter</servlet-class></servlet><servlet-mapping> <servlet-name>GetInitParam</servlet-name> <url-pattern>/initParam</url-pattern></servlet-mapping>
請求轉(zhuǎn)發(fā)
A請求B的資源,B請求C的資源,C返回資源到B,B返回資源到A
請求重定向
A請求B的資源,B返回給A需要去請求C的資源,A請求C的資源(url地址會發(fā)生改變)
public class RequestDispatcher extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext();//獲取上下文 System.out.println("進(jìn)入了請求轉(zhuǎn)發(fā)的方法,url路徑是不變的"); //請求轉(zhuǎn)發(fā)的路徑 javax.servlet.RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/initParam"); //請求轉(zhuǎn)發(fā)執(zhí)行 requestDispatcher.forward(req,resp); }}
web.xml
<servlet> <servlet-name>RequestDispatcher</servlet-name> <servlet-class>com.neil.RequestDispatcher</servlet-class></servlet><servlet-mapping> <servlet-name>RequestDispatcher</servlet-name> <url-pattern>/requestDispatcher</url-pattern></servlet-mapping>
Properties
在Java目錄下新建Java
在resources目錄下新建perperties
發(fā)現(xiàn):都被打包了到了同一個路徑下:classes,我們俗稱這個路徑為classpath:
步驟
在resources里面建立db.properties文件
username="Neil"password="123567"
建立ServletResources類
public class ServletResources extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //在target目錄下找到這個db.properties文件 //關(guān)鍵是在于要用流的形式把它讀取出來 InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); //新建一個properties對象并且把這個輸入流讀取進(jìn)去 Properties properties = new Properties(); properties.load(resourceAsStream); String username = properties.getProperty("username"); String password = properties.getProperty("password"); resp.getWriter().print("username +" + username ); resp.getWriter().print("password +" + password ); }}
建立web.xml設(shè)置路徑
<servlet> <servlet-name>ServletResources</servlet-name> <servlet-class>com.neil.ServletResources</servlet-class></servlet><servlet-mapping> <servlet-name>ServletResources</servlet-name> <url-pattern>/getProperties</url-pattern></servlet-mapping>
Web服務(wù)器接收到客戶端的http請求,會針對這個請求分別創(chuàng)建請求一個代表請求的Request對象和代表響應(yīng)的HttpServletResponse對象
簡單分類(包括HttpServletResponse和它的父類ServletResponse)
負(fù)責(zé)向瀏覽器發(fā)送數(shù)據(jù)的方法
ServletOutputStream getOutputStream() throws IOException;PrintWriter getWriter() throws IOException;
負(fù)責(zé)向瀏覽器發(fā)送響應(yīng)頭的方法
void setCharacterEncoding(String var1);void setContentLength(int var1);void setContentType(String var1);void setDateHeader(String var1, long var2);void addDateHeader(String var1, long var2);void setHeader(String var1, String var2);void addHeader(String var1, String var2);void setIntHeader(String var1, int var2);void addIntHeader(String var1, int var2);void setStatus(int var1);int getStatus();
響應(yīng)狀態(tài)碼也在HttpServletResponse里面
常見應(yīng)用
public class FileServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 1. 獲取下載文件的路徑 String realPath = "/Users/kuifengyuan/Desktop/Java-learn/JavaWeb_servlet/response/target/classes/dongma.jpeg"; System.out.println("下載文件路徑 + " + realPath);// 2. 下載的文件名是啥 String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);// 3. 想辦法讓瀏覽器支持下載我們需要的東西, 讓文件變成中文下載 resp.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(filename,"UTF-8"));// 4. 獲取下載文件的輸入流 FileInputStream fileInputStream = new FileInputStream(realPath);// 5. 創(chuàng)建緩沖區(qū) int len = 0; byte[] buffer = new byte[1024];// 6. 獲取OutPutStream對象 ServletOutputStream outputStream = resp.getOutputStream();// 7. 將FileOutPutStream流寫入到buffer緩沖區(qū),使用OutPutStream將緩沖區(qū)的數(shù)據(jù)輸出到客戶端 while ((len = fileInputStream.read(buffer)) > 0){ outputStream.write(buffer,0,len); } outputStream.close(); fileInputStream.close();// 8. 將OutpuStream緩沖區(qū)的應(yīng)用輸出到客戶端 }}
前端實現(xiàn)
后端實現(xiàn),需要用到Java圖片類,生成一個圖片
public class ImageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //如何讓瀏覽器5秒自動刷新一次? resp.setHeader("refresh","3"); //內(nèi)存中創(chuàng)建圖片 BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); //得到圖片 Graphics2D graphics = (Graphics2D)bufferedImage.getGraphics(); //設(shè)置圖片的背景顏色 graphics.setColor(Color.WHITE); graphics.fillRect(0,0,80,20); //給圖片寫數(shù)據(jù) graphics.setColor(Color.BLUE); graphics.setFont(new Font(null,Font.BOLD,20)); graphics.drawString(makeNum(),0,18); //告訴瀏覽器這個請求用圖片的方式打開 resp.setContentType("image/jpeg"); //網(wǎng)站存在緩存,不讓瀏覽器緩存 resp.setDateHeader("expires",-1); resp.setHeader("Cache-Control","no-cache"); resp.setHeader("Pragma","no-cache"); //把圖片寫給瀏覽器 ImageIO.write(bufferedImage,"jpg",resp.getOutputStream()); } public String makeNum(){ Random random = new Random(); String num = random.nextInt(9999999) + ""; StringBuffer sb = new StringBuffer(); for (int i = 0; i < 7 - num.length(); i++) { sb.append("0"); } String s = sb.toString() + num; return num; }}
常見場景:
用戶登陸
void sendRedirect(String var1) throws IOException;
代碼實現(xiàn)
public class RedirectServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("Location","/response_war/image"); resp.setStatus(302); resp.sendRedirect("/response_war/image"); }}
實現(xiàn)原理:
setHeader(Location,address)
setStatus(int StatusCode)
HttpServletRequest代表客戶端的請求,用戶通過Http協(xié)議訪問服務(wù)器,Http請求中的所有信息都會封裝到 httpServletRequest里面,通過該方法可以獲取客戶端的所有信息
request.getParaemter(String s)
request.getParameterValues(String s)
后端代碼:
public class LoginServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); resp.setCharacterEncoding("utf-8"); String username = req.getParameter("username"); String password = req.getParameter("password"); String[] hobbies = req.getParameterValues("hobby"); System.out.println("==============="); //后臺接收中文亂碼問題 System.out.println(username); System.out.println(password); System.out.println(Arrays.toString(hobbies)); System.out.println("==============="); //通過請求轉(zhuǎn)發(fā) req.getRequestDispatcher("/success.jsp").forward(req,resp); }}
前端代碼:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Helloworld</title></head><body> <h1>Hello Jsp</h1> <div style="text-align: center"> <%--用post方式提交表單,提交我們的login請求--%> <form action="${pageContext.request.contextPath}/login" method="post"> 用戶名:<input type="text" name="username"> <br> 密碼:<input type="password" name="password"><br> 愛好: <input type="checkbox" name="hobby" value="女孩">女孩 <input type="checkbox" name="hobby" value="唱歌">唱歌 <input type="checkbox" name="hobby" value="電影">電影 <input type="checkbox" name="hobby" value="代碼">代碼 <input type="submit"> </form> </div></body></html>
面試題:重定向和轉(zhuǎn)發(fā)的區(qū)別
相同點:
不同點:
會話:用戶打開一個瀏覽器,點擊了很多超鏈接,訪問了多個web資源,關(guān)閉瀏覽器,這個過程可以稱之為會話
有狀態(tài)會話:一個同學(xué)來過教室,下次再來教室,我們會知道這個同學(xué)曾經(jīng)來過,稱之為有狀態(tài)會話
一個網(wǎng)站如何證明來過?
客戶端 服務(wù)端
常見場景:網(wǎng)站登陸后,你下次不用再登陸了,第二次訪問直接上去
從請求中拿到cookie信息
服務(wù)器響應(yīng)給客戶端cookie
/*常用cookie方法*///Cookie,服務(wù)器端從客戶端獲取Cookie[] cookies = req.getCookies(); //這里返回數(shù)組,表示cookies可能存在多個cookie.getName(); //獲得cookie中的keycookie.getValue(); //獲得cookie中的value//服務(wù)器給客戶端發(fā)一個cookiesCookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");//設(shè)置成一天的有效期cookie.setMaxAge(24*60*60);resp.addCookie(cookie);
//保存用戶上一次訪問的時間public class cookie extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //服務(wù)器,告訴你,你來的時間,把這個時間封裝成為一個信件,你下次帶著來,我就知道你來了 //解決中文亂碼問題 req.setCharacterEncoding("GBK"); resp.setCharacterEncoding("GBK"); PrintWriter out = resp.getWriter(); //Cookie,服務(wù)器端從客戶端獲取 Cookie[] cookies = req.getCookies(); //這里返回數(shù)組,表示cookies可能存在多個 //判斷cookies是否存在 if(cookies != null){ out.write("你上一次訪問的時間是:"); for (Cookie cookie : cookies) { //獲取cookies的名字 String name = cookie.getName(); System.out.println("這個cookies的名字是 " + name); if(name.equals("lastLoginTime")){ //獲取cookies的值 System.out.println(cookie.getValue() + ""); long l = Long.parseLong(cookie.getValue()); Date date = new Date(l); out.write(String.valueOf(date)); } } }else { out.write("這是您第一次訪問本站"); } //服務(wù)器給客戶端發(fā)一個cookies Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+""); //設(shè)置成一天的有效期 cookie.setMaxAge(24*60*60); resp.addCookie(cookie); }}
cookie:一般會保存在本地的用戶目錄下的appdata下
細(xì)節(jié)問題
刪除Cookie:
數(shù)據(jù)傳輸過程中的中文亂碼問題:
/*使用URLEncoder.encode(String s, String type)*/URLEncoder.encode("鋼鐵俠","utf-8"); //會返回一個中文編碼過的字符串/*解碼*/URLDecoder.decode(cooie.getValue,"utf-8"); //會解碼成一個中文編碼的字符串
什么是Session:
Session與Cookie的區(qū)別:
兩種設(shè)置session過去的方式:
后端寫session.invalidate();
web.xml
<!--設(shè)置Session默認(rèn)的失效時間--> <session-config> <!--1分鐘之后session自動生效--> <session-timeout>1</session-timeout> </session-config>
使用場景:
案例:
public class SessionDemo01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //解決亂碼問題 resp.setCharacterEncoding("utf-8"); req.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); //從req里面得到Session HttpSession session = req.getSession(); //給Session中存東西 session.setAttribute("name",new Person("Neill",24)); //獲取Session的ID String id = session.getId(); //判斷session是不是新創(chuàng)建的 if( session.isNew() ){ resp.getWriter().write("session創(chuàng)建成功,Id為:" + id); }else { resp.getWriter().write("已經(jīng)在服務(wù)器存在session,Id為:" + id); } //session創(chuàng)建的時候做了什么事情?創(chuàng)建了一個cookie保存了session的id Cookie cookie = new Cookie("JSESSIONID",id); //獲取session Person getPerson = (Person)session.getAttribute("name"); //手動注銷Session session.invalidate(); }}
Java Server Pages:Java服務(wù)器端頁面,也和Servlet一樣用于開發(fā)動態(tài)Web技術(shù)
最大的特點:
思路:jsp到底如何執(zhí)行的!
瀏覽器向服務(wù)器發(fā)送請求,不管訪問什么資源,都是訪問Servlet
而JSP繼承了HttpJspBase這個類,而HttpJspBase這個類繼承了HttpServlet
JSP最終會轉(zhuǎn)換成一個java類得出結(jié)論:
得出結(jié)論:JSP本質(zhì)上就是servlet
輸出頁面前增加的代碼
response.setContentType("text/html"); //設(shè)置響應(yīng)的頁面類型pageContext = _jspxFactory.getPageContext(this,request,response,null,true,8192,true);_jspx_page_context = pageContext;application = pageContext.getServletContext();config = pageContext.getServletConfig();session = pageContext.getSession();out = pageContext.getOut();_jspx_out = out;
以上對象可以在jsp頁面中直接使用
在JSP中,只要是Java代碼就會被原封不動的輸出,如果是HTML代碼,就會被轉(zhuǎn)換成
out.write("<html>\r\n");
輸出到前端
任何語言都有自己的語法。JSP作為java技術(shù)的一種應(yīng)用,它擁有一些自己擴(kuò)充的語法,它擁有一些自己擴(kuò)充的語法(了解即可),java所有語法都支持!
JSP表達(dá)式
<%--JSP表達(dá)式: 一般用來將程序輸出到客戶端 <%= new 變量或者表達(dá)式%>--%> <%= new java.util.Date()%>
腳本片段
<%--JSP腳本片段:--%><% int sum = 0; for (int i = 0; i < 100; i++) { sum+=i; } out.println("<h1>" + sum + "<h1>");%>
在代碼中嵌入HTML元素
<%--在代碼中嵌入HTML元素--%> <% for (int i = 0; i < 5; i++) { %> <h1>Hello Neil</h1> <% } %>
JSP聲明
<%! static { System.out.println("123123")}private int golabalvar = 0;public void Neil(){ System.out.println("進(jìn)入了這個方法") }%>
JSP聲明:會被編譯到JSP生成Java類中,其他的會生成到_jspServeice_方法之中
<%@ page errorPage="error/500.jsp" %> <!--在頭部定義錯誤跳轉(zhuǎn)--><%@ page isErrorPage="true" %> <!--顯示定義這是一個錯誤頁面-->
或者在web.xml定義
<error-page> <error-code>404</error-code> <location>/error/404.jsp</location></error-page><error-page> <error-code>500</error-code> <location>/error/500.jsp</location></error-page>
引用外部頁面
<!--@include會將兩個頁面合二為一,可能會產(chǎn)生兩個jsp頁面的參數(shù)重名等問題--><%@include file ="common/header.jsp"%><!--推薦使用這個--><!--jsp標(biāo)簽,jsp:include:拼接頁面,本質(zhì)還是三個--><jsp:include page ="common/header.jsp">
PageContext
存東西:保存的數(shù)據(jù)只在一個頁面中有效,但是可以設(shè)置作用域,如下例Request
:存東西:客戶端向服務(wù)端產(chǎn)生的請求,產(chǎn)生的數(shù)據(jù)客戶看完就沒用的,比如新聞Response
Session
存東西:產(chǎn)生的數(shù)據(jù),用戶用完了需要保存在服務(wù)器,比如購物車Application
(實際是ServletContext
) 存東西:用戶用完了其他用戶還可能使用Config
(實際是ServletConfig
)Out
Page
Exception
<% pageContext.setAttribute("name1","Neil1"); //保存的數(shù)據(jù)只在一個頁面中有效 request.setAttribute("name2","Neil222"); //保存的數(shù)據(jù)只在一次請求中有效,請求轉(zhuǎn)發(fā)會攜帶這個對象 session.setAttribute("name3","Neil3333"); //在一次會話中有效,session為了用戶服務(wù),所以每一個用戶有一個session從打開瀏覽器到關(guān)閉瀏覽器 application.setAttribute("name4","Neil44444"); //凌駕于所有之上,保存的數(shù)據(jù)在服務(wù)器中有效,從打開服務(wù)器到關(guān)閉服務(wù)器%><% /*腳本片段中的代碼會被生成到j(luò)sp.java中*/ /*通過尋找方式取*/ String name1 = (String)pageContext.findAttribute("name1"); String name2 = (String)pageContext.findAttribute("name2"); String name3 = (String)pageContext.findAttribute("name3"); String name4 = (String)pageContext.findAttribute("name4"); String name5 = (String)pageContext.findAttribute("name5");%><%--使用EL表達(dá)式輸出 ${}}--%> <h1>取出的值為:</h1> <h3>${name1}</h3> <h3>${name2}</h3> <h3>${name3}</h3> <h3>${name4}</h3>
<% /* * public void setAttribute(String name, Object attribute, int scope) { switch(scope) { case 1: this.mPage.put(name, attribute); break; case 2: this.mRequest.put(name, attribute); break; case 3: this.mSession.put(name, attribute); break; case 4: this.mApp.put(name, attribute); break; default: throw new IllegalArgumentException("Bad scope " + scope); } public static final int PAGE_SCOPE = 1; public static final int REQUEST_SCOPE = 2; public static final int SESSION_SCOPE = 3; public static final int APPLICATION_SCOPE = 4; }*/ //第三個為作用域,可以設(shè)置作用域 pageContext.setAttribute("name","Neil",SESSION_SCOPE);pageContext.forward("/index"); %>
EL表達(dá)式
${param.username}
JSP標(biāo)簽
<jsp:forward page="jsptag2.jsp"> <jsp:param name="name" value="Neil"/> <jsp:param name="age" value="12"/></jsp:forward>
JSTL標(biāo)簽
jstl的標(biāo)簽庫是為了彌補(bǔ)html標(biāo)簽的不足,它自定義了許多的標(biāo)簽,標(biāo)簽的功能可以供我們使用
菜鳥文檔:
實體類
JavaBean有特定的寫法:
一般用來和數(shù)據(jù)庫的字段做映射:ORM
ORM:對象關(guān)系映射
<jsp:useBean id="people1" class="com.neil.entity.People" scope="page"/> <jsp:setProperty name="people1" property="address" value="重慶"/> <jsp:setProperty name="people1" property="id" value="1"/> <jsp:setProperty name="people1" property="age" value="3"/> <jsp:setProperty name="people1" property="name" value="Neillll"/>地址:<jsp:getProperty name="people1" property="address" /> id:<jsp:getProperty name="people1" property="id" /> 年齡:<jsp:getProperty name="people1" property="age"/> 名字:<jsp:getProperty name="people1" property="name"/>
什么是MVC:模型(Model)、視圖(View)、控制器(Controller)
用戶直接訪問控制層,控制層就可以直接操作數(shù)據(jù)庫
servlet–CRUD–>數(shù)據(jù)庫
弊端:
Model
View
Controller(Servlet)
接收用戶的請求
交給業(yè)務(wù)層處理對應(yīng)的代碼
控制視圖的跳轉(zhuǎn)
登陸--> 接收用戶的請求 --->處理用戶請求以及獲得登陸的參數(shù)---> 交給業(yè)務(wù)層處理登陸業(yè)務(wù)(判斷用戶名密碼是否正確:事務(wù)) ----> Dao層查詢用戶名和密碼是否正確 ---> 數(shù)據(jù)庫
Filter:過濾器,用來過濾網(wǎng)站的數(shù)據(jù)
Filter開發(fā)步驟:
public class CharacterEncodingFilter implements Filter { //初始化 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("已經(jīng)初始化"); } //Chain:過濾器中的所有代碼在過濾特定請求的時候都會執(zhí)行 //必須要讓過濾器繼續(xù)通行 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=utf-8"); System.out.println("CharacterEncoding執(zhí)行前...."); filterChain.doFilter(servletRequest,servletResponse); //讓我們的請求繼續(xù)走,如果不寫,程序到這里就被攔截停止了 System.out.println("CharacterEncoding執(zhí)行后...."); } //銷毀 public void destroy() { System.out.println("已經(jīng)銷毀"); }}
Web.xml
<filter> <filter-name>CharacterEncoding</filter-name> <filter-class>com.neil.filter.CharacterEncodingFilter</filter-class></filter><filter-mapping> <filter-name>CharacterEncoding</filter-name> <!--只要經(jīng)過/servlet/*的任何請求都要經(jīng)過過濾器--> <url-pattern>/servlet/*</url-pattern></filter-mapping>
用戶登陸之后才能進(jìn)入主頁!用戶注銷之后就不能進(jìn)入主頁了
public class SysFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; Object user_session = httpServletRequest.getSession().getAttribute(USER_SESSION); if(user_session == null){ httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/error.jsp"); } filterChain.doFilter(servletRequest,servletResponse); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { }}
web.xml
<filter> <filter-name>SysFilter</filter-name> <filter-class>com.neil.filter.SysFilter</filter-class></filter><filter-mapping> <filter-name>SysFilter</filter-name> <url-pattern>/sys/*</url-pattern></filter-mapping>
項目結(jié)構(gòu)
實現(xiàn)一個監(jiān)聽器接口:(有N種)
//統(tǒng)計網(wǎng)站在線人數(shù),統(tǒng)計sessionpublic class OnlineCountListener implements HttpSessionListener { //一旦創(chuàng)建一個session,就會出發(fā)一次這個事件 @Override public void sessionCreated(HttpSessionEvent se) { ServletContext servletContext = se.getSession().getServletContext(); Integer onlineCount =(Integer) servletContext.getAttribute("OnlineCount"); if(onlineCount==null){ onlineCount = 1; }else { int count = onlineCount + 1; } servletContext.setAttribute("onlineCount",onlineCount); } //一旦銷毀就會觸發(fā)這個事件 //兩種session銷毀方式: //1. 手動銷毀 session.invalidate(); //2. 自動銷毀,在web.xml配置自動銷毀時間 @Override public void sessionDestroyed(HttpSessionEvent se) { ServletContext servletContext = se.getSession().getServletContext(); Integer onlineCount =(Integer) servletContext.getAttribute("OnlineCount"); if(onlineCount==null){ onlineCount = 0; }else { int count = onlineCount - 1; } servletContext.setAttribute("onlineCount",onlineCount); }}
Web.xml
<listener> <listener-class>com.neil.listener.OnlineCountListener</listener-class></listener>
對于文件上傳,瀏覽器在上傳的過程中是將文件以流的形式提交到服務(wù)器的。
一般采用apache的開源工具common-fileupload這個文件上傳組件
common-fileupload依賴于common-io包
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --><dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version></dependency><!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version></dependency>
【文件上傳的注意事項】
【需要用到的類】
ServletFileUpload
負(fù)責(zé)處理上傳的文件數(shù)據(jù),并將表單中每個輸入項封裝成一個FileItem
對象,在使用ServletFileUpload
對象解析請求時需要DiskFileItemFactory
對象。隨意我們需要進(jìn)行工作前需要構(gòu)建好DiskFileItemFacotry
對象,通過ServletFileUpload
對象的構(gòu)造方法或setFileItemFactory()
方法設(shè)置ServletFileUpload
對象的fileItemFactory
屬性。
【FileItem類】
在html頁面input必須有name<input type="file" name="filename">
**表單如果包含一個文件上傳輸入項的話,這個表單的enctype屬性就必須設(shè)置為multipart/form-data **
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post"> <input type="text" name="username"> <input type="file" name="file1"> <input type="file" name="file2"> <input type="submit" value="提交"></form>
【常用方法介紹】
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><body><h2>Hello World!</h2> <%--通過表單上傳文件--%> <%--GET: 上傳文件大小有限制 POST:沒有限制--%> <form action="" method="post" enctype="multipart/form-data"> 上傳用戶:<input type="text" name="userName"> <p><input type="file" name="file1"></p> <button type="submit">提交</button> | <button type="reset" >重制</button> </form></body></html>
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> <!--JSP依賴--> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> </dependencies>
SMTP協(xié)議
發(fā)送郵件:
我們通常把處理用戶smtp請求(郵件發(fā)送請求)的服務(wù)器稱之為SMTP服務(wù)器(郵件發(fā)送服務(wù)器)
POP3協(xié)議
接收郵件:
我們通常把處理用戶pop3請求(郵件接收請求)的服務(wù)器叫做pop3服務(wù)器(郵件接收服務(wù)器)
流程圖:
需要準(zhǔn)備:
JavaMail APi
和Java Activation Framework
public class EmailDemo01 { //簡單郵件:沒有附件和圖片 //復(fù)雜郵件:有附件和圖片 //要發(fā)送郵件,需要獲得協(xié)議的支持:開啟pop3/SMTP服務(wù)器 //獲得一個授權(quán)碼 public static void main(String[] args) throws Exception { Properties prop = new Properties(); prop.setProperty("mail.host","smtp.qq.com"); //設(shè)置qq郵件服務(wù)器 prop.setProperty("mail.transport.protocol","smtp"); //郵件發(fā)送協(xié)議 prop.setProperty("mail.smtp.auth","true"); //需要驗證用戶名密碼 //關(guān)于QQ郵箱,還要設(shè)置SSL加密,加上一下代碼即可,其他郵箱不需要 MailSSLSocketFactory mailSSLSocketFactory = new MailSSLSocketFactory(); mailSSLSocketFactory.setTrustAllHosts(true); prop.put("mail.smtp.ssl.enable","true"); prop.put("mail.smtp.ssl.socketFactory",mailSSLSocketFactory); //使用JavaMail的五個步驟 //1、創(chuàng)建定義整個應(yīng)用所需要的環(huán)境信息的session對象 Session session = Session.getDefaultInstance(prop, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("xxx@163.com","授權(quán)碼"); } }); session.setDebug(Boolean.TRUE); //2、通過session對象獲得transport對象 Transport transport = session.getTransport(); //3、使用郵箱的用戶名和授權(quán)碼連上郵件服務(wù)器 transport.connect("smtp.qq.com","xxx@qq.com","授權(quán)碼"); //4、創(chuàng)建郵件,MimeMessage是Message的實現(xiàn)類 Message message = new MimeMessage(session); message.setSubject("Hello, this is a simple email from Java");//收件人 message.setFrom(new InternetAddress("xxx@qq.com")); //發(fā)件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress("xxx@163.com"));//設(shè)置郵件的收件人 message.setContent("<h1 style='color:red'>This is the content!!</h1>","text/html;charset=utf-8"); //5、發(fā)送郵件 transport.sendMessage(message,message.getAllRecipients()); //6、關(guān)閉鏈接 transport.close(); }}
MIME(多用途互聯(lián)網(wǎng)郵件擴(kuò)展類型)
MimeBodyPart
class表示一個MIME信息,它和MimeMessage類一樣都是從Part接口繼承過來。
MimeMultiPart
class是抽象類Multipart的實現(xiàn)子類,用來組合多個MIME信息。一個MimeMultipart
對象可以包含多個代表MIME
消息的 MimeBodyPart
對象
public class EmailDemo01 { //簡單郵件:沒有附件和圖片 //復(fù)雜郵件:有附件和圖片 //要發(fā)送郵件,需要獲得協(xié)議的支持:開啟pop3/SMTP服務(wù)器 //獲得一個授權(quán)碼 public static void main(String[] args) throws Exception { Properties prop = new Properties(); prop.setProperty("mail.host","smtp.qq.com"); //設(shè)置qq郵件服務(wù)器 prop.setProperty("mail.transport.protocol","smtp"); //郵件發(fā)送協(xié)議 prop.setProperty("mail.smtp.auth","true"); //需要驗證用戶名密碼 //關(guān)于QQ郵箱,還要設(shè)置SSL加密,加上一下代碼即可,其他郵箱不需要 MailSSLSocketFactory mailSSLSocketFactory = new MailSSLSocketFactory(); mailSSLSocketFactory.setTrustAllHosts(true); prop.put("mail.smtp.ssl.enable","true"); prop.put("mail.smtp.ssl.socketFactory",mailSSLSocketFactory); //使用JavaMail的五個步驟 //1、創(chuàng)建定義整個應(yīng)用所需要的環(huán)境信息的session對象 Session session = Session.getDefaultInstance(prop, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("some@163.com","授權(quán)碼"); } }); session.setDebug(Boolean.TRUE); //2、通過session對象獲得transport對象 Transport transport = session.getTransport(); //3、使用郵箱的用戶名和授權(quán)碼連上郵件服務(wù)器 transport.connect("smtp.qq.com","some@qq.com","授權(quán)碼"); //4、創(chuàng)建郵件,MimeMessage是Message的實現(xiàn)類 Message message = new MimeMessage(session); message.setSubject("Hello, this is a complex email from Java. Pay attention to the attachment");//收件人 //準(zhǔn)備圖片數(shù)據(jù) message.setFrom(new InternetAddress("email@qq.com")); //發(fā)件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress("xxx@qq.com"));//設(shè)置郵件的收件人 //===================================簡單郵件設(shè)置內(nèi)容============================================= //message.setContent("<h1 style='color:red'>This is the content!!</h1>","text/html;charset=utf-8"); //===================================帶內(nèi)嵌資源的變更============================================= MimeBodyPart MimeBodyPartImage = new MimeBodyPart(); //圖片需要經(jīng)過數(shù)據(jù)處理 DataHandler dataHandler = new DataHandler(new FileDataSource("source")); MimeBodyPartImage.setDataHandler(dataHandler); //在我們的主體中放入我們處理的圖片數(shù)據(jù) MimeBodyPartImage.setContentID("Mashaladi"); //給圖片設(shè)置一個ID,在后面可以使用 //===================================設(shè)置附件的變更============================================= MimeBodyPart MimeBodyPartAttachment = new MimeBodyPart(); DataHandler dataHandler2 = new DataHandler(new FileDataSource("source")); MimeBodyPartAttachment.setDataHandler(dataHandler2); //在我們的主體中放入我們處理的圖片數(shù)據(jù) MimeBodyPartAttachment.setFileName("MarkDown Notes"); //給附件設(shè)置一個名字,該名字會顯示在接收方附件中國呢 //===================================設(shè)置附件的變更============================================= //準(zhǔn)備正文數(shù)據(jù) MimeBodyPart MimeBodyPartText = new MimeBodyPart(); //cid:contentID,對應(yīng)以上的setContentID MimeBodyPartText.setContent("Hello World!! 這封附件是你喜歡的喲,這是給你的禮物~?? <img src='cid:Mashaladi'>","text/html;charset=utf-8"); //===================================數(shù)據(jù)拼裝郵件正文內(nèi)容============================================= //提供描述關(guān)系 MimeMultipart mimeMultipart = new MimeMultipart(); mimeMultipart.addBodyPart(MimeBodyPartImage); mimeMultipart.addBodyPart(MimeBodyPartText); //設(shè)置描述關(guān)系,這里可以設(shè)置成related,內(nèi)嵌,參照上圖。如果需要附件資源,直接寫mixed mimeMultipart.setSubType("mixed"); MimeBodyPart contentText = new MimeBodyPart(); contentText.setContent(mimeMultipart); //拼裝附件 MimeMultipart completeFile = new MimeMultipart(); completeFile.addBodyPart(contentText); completeFile.addBodyPart(MimeBodyPartAttachment); //設(shè)置到消息中,保存修改 message.setContent(completeFile); message.saveChanges(); //===================================帶內(nèi)嵌資源的變更============================================= //5、發(fā)送郵件 transport.sendMessage(message,message.getAllRecipients()); //6、關(guān)閉鏈接 transport.close(); }}
參考文獻(xiàn):本篇學(xué)習(xí)筆記主要總結(jié)于bilibili up主 “狂神學(xué)Java” 的系列視頻— 【狂神說Java】JavaWeb從入門到實戰(zhàn)