整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Java Web輕松學40 - JSP初步使用

          Java Web輕松學40 - JSP初步使用
          本系列文章旨在記錄和總結自己在Java Web開發之路上的知識點、經驗、問題和思考,希望能幫助更多(Java)碼農和想成為(Java)碼農的人。
          

          1. 介紹
          2. 租房網現狀
          3. 思路
          4. 共享模擬數據的Filter
          5. 房源列表頁面 - houses.jsp
          6. 驗證
          7. 房源詳情頁面 - house-details.jsp
          8. 房源編輯表單頁面 - house-form.jsp
          9. 處理房源編輯表單的提交 - HouseFormServlet
          10. 進一步改進 - include.jsp
          11. 總結

          介紹

          上篇文章介紹了JSP的核心原理,本篇文章準備介紹JSP的初步使用。

          大家一定要自己動手編寫代碼,運行驗證,只有這樣才能理解的更加透徹,印象也更加深刻。不知道大家有沒有這樣一種體會,就是明明自己看了不少技術相關的書籍,但是每到用的時候就忘記了相關技術如何使用,還是需要不斷的上網搜索。

          這還是說明我們動手實踐比較少。在我看來,任何一門科學、技術、學問、專業都離不開以下四個環節:

          • 看資料、跟師傅,學習前人發現/發明的正確理論、總結的正確經驗,系統化地和碎片化地(比如上課、報班、看書、互聯網上的資訊和專欄等等)。
          • 身體力行,動手實踐。
          • 經常思考和總結,多問幾個為什么,多想想如何能更快更好的解決問題,想想自己是否能發明或發現新概念、新理論、新模型、新體系、新方法等等,可以利用發散思維、逆向思維等等。
          • 不斷記錄自己的學習體會、實踐的過程和結論、思考和總結的過程和成果,可以簡單的記錄,也可以系統的記錄,甚至可以寫成書。

          任何一門科學、技術、學問、專業都不是一日之功,需要長期的堅持這四個環節,所以必須從小就灌輸,養成學、做、思、記的習慣。這四個環節是互相影響、互相交叉、互相促進、需要同時進行,不可偏廢的。正所謂“紙上得來終覺淺,絕知此事要躬行”、“學而不思則罔,思而不學則殆”、“好記性不如爛筆頭”等等。

          雖說這四個環節不可偏廢,但各門科學、技術、學問、專業還是有所側重的,比如科學這個詞感覺就偏理論學習和思考多一些,動手實踐少一些;而技術這個詞就相反。再比如工科偏動手實踐多一些,理科偏理論研究多一些等等。

          不好意思,又跑題。說那么多無非就是想說我們需要多敲敲代碼。軟件/編程這一行業被劃分到工科,那就說明我們更要多動手實踐。話說這應該是實踐成本最低的工科行業了,只要一臺個人電腦即可,還有各種開源的軟件可用,要是建筑、土木、工業制造、各種勘探、化工、電力等等,要么需要去實地、要么需要建個實驗室、要么需要買個機床。。。。。。

          好了,不說廢話了。我們仍然以前面開發的租房網應用(可以參考這篇文章和這篇文章)為基礎,使用JSP技術來改造,至少需要達到的一個目標是讓代碼看起來更加清爽。

          租房網現狀

          工程結構:

          靜態資源 - 登錄頁面login.html:

          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="UTF-8">
          <title>租房網 - 登錄</title>
          </head>
          <body>
          	<form action="login.servlet" method="post">
          		<label for="user_name">用戶名:</label><input type="text" id="user_name" name="userName" />
          		<label for="password">密碼:</label><input type="password" id="password" name="password" />
          		<input type="submit" value="登錄" />
          	</form>
          </body>
          </html>
          

          房源實體類 - House.java:

          package houserenter.entity;
          public class House {
          	private String id;
          	private String name;
          	private String detail;
          	public House(String id, String name, String detail) {
          		super();
          		this.id=id;
          		this.name=name;
          		this.detail=detail;
          	}
          	public String getId() {
          		return id;
          	}
          	public void setId(String id) {
          		this.id=id;
          	}
          	public String getName() {
          		return name;
          	}
          	public void setName(String name) {
          		this.name=name;
          	}
          	public String getDetail() {
          		return detail;
          	}
          	public void setDetail(String detail) {
          		this.detail=detail;
          	}
          	@Override
          	public String toString() {
          		return "House [id=" + id + ", name=" + name + ", detail=" + detail + "]";
          	}
          }
          

          處理登錄請求的Servlet - LoginServlet.java:

          package houserenter.servlet;
          import java.io.IOException;
          import javax.servlet.ServletException;
          import javax.servlet.annotation.WebServlet;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          @WebServlet("/login.servlet")
          public class LoginServlet extends HttpServlet {
          	private static final long serialVersionUID=1L;
          	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          		String userName=request.getParameter("userName");
          		String password=request.getParameter("password");
          		
          		//這里需要驗證用戶是否已經注冊,省略
          		System.out.println("userName: " + userName + ", password: " + password);
          		
          		//用戶登錄成功,重定向到房源列表頁面
          		response.sendRedirect("house.html?userName=" + userName);
          	}
          }
          

          處理房源相關請求(房源查找、房源詳情、房源編輯)的Servlet - HouseServlet.java:

          package houserenter.servlet;
          import java.io.IOException;
          import java.io.PrintWriter;
          import java.util.ArrayList;
          import java.util.List;
          import javax.servlet.ServletException;
          import javax.servlet.annotation.WebServlet;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import houserenter.entity.House;
          @WebServlet("/house.html")
          public class HouseServlet extends HttpServlet {
          	private static final long serialVersionUID=1L;
          	
          	private List<House> mockHouses;
          	@Override
          	public void init() {
          		mockHouses=new ArrayList<House>();
          		mockHouses.add(new House("1", "金科嘉苑3-2-1201", "詳細信息"));
          		mockHouses.add(new House("2", "萬科橙9-1-501", "詳細信息"));
          	}
          	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          		String userName=request.getParameter("userName");
          		PrintWriter writer=response.getWriter();
          		
          		writer.println("<!DOCTYPE html>");
          		writer.println("<html>");
          		writer.println("<head>");
          		writer.println("<meta charset=\"UTF-8\">");
          		writer.println("<title>租房網</title>");
          		writer.println("</head>");
          		writer.println("<body>");
          		
          		writer.println("<h1>你好,"+userName+"!歡迎來到租房網! <a href=\"login.html\">退出</a></h1>");
          		writer.println("<br><br>");
          		
          		String houseId=request.getParameter("houseId");
          		String editHouse=request.getParameter("editHouse");
          		
          		if (houseId==null || houseId.isEmpty()) {
          			//查找該用戶感興趣的房源,這里省略
          			System.out.println("userName: " + userName + " access house.html!");
          			writer.println("<h6>共找到你感興趣的房源 "+mockHouses.size()+" 條</h6>");
          			writer.println("<ul>");
          			for (House house : mockHouses) {
          				writer.println("<li><h2><a href=\"house.html?userName="+userName+"&houseId="+house.getId()+"\">"+house.getName()+"</a></h2></li>");
          			}
          			writer.println("</ul>");
          		} else if (editHouse==null) {
          			//根據houseId查找該房源的詳細信息
          			System.out.println("userName: " + userName + " access house.html for house detail!");
          			House target=null;
          			for (House house : mockHouses) {
          				if (houseId.equals(house.getId())) {
          					target=house;
          					break;
          				}
          			}
          			
          			writer.println("<h2>"+target.getName()+"<a href=\"house.html?userName="+userName+"&houseId="+houseId+"&editHouse=true\">編輯</a></h2>");
          			writer.println("<h3>"+target.getDetail()+"</h3>");
          			writer.println("<h4><a href=\"house.html?userName="+userName+"\">回到列表</a></h4>");
          		} else {
          			//存在editHouse參數,返回指定房源的編輯頁面
          			System.out.println("userName: " + userName + " access house.html to edit house!");
          			House target=null;
          			for (House house : mockHouses) {
          				if (houseId.equals(house.getId())) {
          					target=house;
          					break;
          				}
          			}
          			//writer.println("<form action=\"house.html?userName="+userName+"&houseId="+houseId+"\" method=\"post\">");
          			writer.println("<form action=\"house.html\" method=\"post\">");
          			writer.println("<input type=\"hidden\" name=\"userName\" value=\""+userName+"\"/>");
          			writer.println("<input type=\"hidden\" name=\"houseId\" value=\""+houseId+"\"/>");
          			writer.println("<label for=\"house_name\">房源名字:</label><input type=\"text\" id=\"house_name\" name=\"houseName\" value=\""+target.getName()+"\" />");
          			writer.println("<label for=\"house_detail\">房源詳細信息:</label><input type=\"text\" id=\"house_detail\" name=\"houseDetail\" value=\""+target.getDetail()+"\" />");
          			writer.println("<input type=\"submit\" value=\"提交\" />");
          			writer.println("</form>");
          		}
          		
          		writer.println("</body>");
          		writer.println("</html>");
          	}
          	
          	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          		String userName=request.getParameter("userName");
          		String houseId=request.getParameter("houseId");
          		
          		//獲取提交的房源信息,并保存
          		System.out.println("userName: " + userName + " access house.html to save house detail!");
          		String houseName=request.getParameter("houseName");
          		String houseDetail=request.getParameter("houseDetail");
          		for (House house : mockHouses) {
          			if (houseId.equals(house.getId())) {
          				house.setName(houseName);
          				house.setDetail(houseDetail);
          				break;
          			}
          		}
          		
          		response.sendRedirect("house.html?userName="+userName+"&houseId="+houseId);
          	}
          }
          

          設置請求響應編碼、登錄驗證的Filter - MyFirstFilter.java:

          package houserenter.filter;
          import java.io.IOException;
          import javax.servlet.Filter;
          import javax.servlet.FilterChain;
          import javax.servlet.ServletException;
          import javax.servlet.ServletRequest;
          import javax.servlet.ServletResponse;
          import javax.servlet.annotation.WebFilter;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          @WebFilter("/house.html")
          public class MyFirstFilter implements Filter {
          	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          		request.setCharacterEncoding("UTF-8");
          		response.setCharacterEncoding("UTF-8");
          		
          		HttpServletRequest httpServletRequest=(HttpServletRequest) request;
          		HttpServletResponse httpServletResponse=(HttpServletResponse) response;
          		
          		String userName=httpServletRequest.getParameter("userName");
          		
          		if (userName==null || userName.isEmpty()) {
          			System.out.println("invalid user!");
          			httpServletResponse.sendRedirect("login.html");
          		} else {
          			chain.doFilter(request, response);
          		}
          	}
          }
          

          思路

          登錄頁面和LoginServlet目前還算簡單,暫時可以不用改造。

          HouseServlet的代碼量稍微有點多(也不過一百多行),且夾雜著輸出HTML內容,看著比較亂。從功能上來說雖然都與房源有關,但實際上動態生成的呈現給瀏覽器的是三個頁面(房源列表、房源詳情、房源編輯),所以可以考慮用三個JSP頁面代替,咱就命名為:

          • houses.jsp
          • house-details.jsp
          • house-form.jsp

          另外,因為涉及到一個房源編輯的表單,所以需要一個Servlet來處理表單的提交,就叫HouseFormServlet吧。

          還有一個要提的是HouseServlet初始化了一些模擬數據,那這部分應該放在哪呢?因為一個JSP頁面就相當于一個Servlet,所以原來的HouseServlet現在要改造成三個JSP頁面,感覺模擬數據放在哪個JSP頁面都不太合適,因為三個JSP頁面都要訪問同一份模擬數據才行。

          于是問題變為:如何在多個JSP頁面之間共享訪問同一份數據?我先想到的是能不能在一個Filter中初始化模擬數據,然后讓它攔截到這三個JSP頁面的請求,然后在請求中使用setAttribute()方法將模擬數據掛上去,最后在JSP頁面中使用請求的getAttribute()方法取出來。

          好了,既然思路有了,那我們就大刀闊斧的干吧。

          不過我們可以把之前的代碼都保留著,另外編寫新添加的JSP頁面和Filter即可,當然也可以把之前的都刪掉。

          共享模擬數據的Filter

          這次我們先編寫我們的Filter。

          在Filter中初始化模擬數據跟之前在HouseServlet中是類似的。Filter也有一個相同的生命周期方法init()(另一個相同的是destroy()方法),大家可以直接看看Filter的源碼(如何查看源碼可以參考這篇文章)。

          不過Filter的這個init()方法是Servlet容器初始化Filter的時候就調用,與Servlet的init()方法在第一個請求到來時才調用是不同的。

          Filter的doFilter()方法還是可以跟之前的Filter一樣設置請求響應的編碼以及進行登錄驗證,但最主要的是調用請求的setAttribute()方法把模擬數據掛載到該請求中。

          在Eclipse中創建Filter還是可以使用New工具(可以參考這篇文章中的新建Java類部分),大家應該很容易知道該怎么填寫相關信息,比如Filter的類名、初始化參數、映射(即攔截何種請求)。當然,你也可以新建空白的文件手動敲寫所有代碼。

          package houserenter.filter;
          import java.io.IOException;
          import java.util.ArrayList;
          import java.util.List;
          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;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import houserenter.entity.House;
          @WebFilter(
          		urlPatterns={ 
          				"/houses.jsp", 
          				"/house-details.jsp", 
          				"/house-form.jsp",
          				"house-form.servlet"
          		})
          public class MySecondFilter implements Filter {
          	private List<House> mockHouses;
          	@Override
          	public void init(FilterConfig filterConfig) {
          		System.out.println("AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
          		mockHouses=new ArrayList<House>();
          		mockHouses.add(new House("1", "金科嘉苑3-2-1201", "詳細信息"));
          		mockHouses.add(new House("2", "萬科橙9-1-501", "詳細信息"));
          	}
          	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          		System.out.println("BBBBBBBBBBBBBBBBBBBBBBBBBBBB");
          		request.setCharacterEncoding("UTF-8");
          		response.setCharacterEncoding("UTF-8");
          		
          		HttpServletRequest httpServletRequest=(HttpServletRequest) request;
          		HttpServletResponse httpServletResponse=(HttpServletResponse) response;
          		
          		Object obj=httpServletRequest.getAttribute("mockHouses");
          		if (obj==null) {
          			httpServletRequest.setAttribute("mockHouses", mockHouses);
          		}
          		
          		String userName=httpServletRequest.getParameter("userName");
          		
          		if (userName==null || userName.isEmpty()) {
          			System.out.println("invalid user!");
          			httpServletResponse.sendRedirect("login.html");
          		} else {
          			chain.doFilter(request, response);
          		}
          	}
          }
          

          上面的代碼是我用New工具生成之后,把無用的注釋、成員方法刪掉之后,再加上初始化模擬數據的邏輯、doFilter的邏輯。

          因為Filter接口的init()方法和destroy()方法是default的(JDK8才支持),因此可以不必實現。

          注意,此Filter攔截的有哪些資源的訪問請求!

          doFilter的邏輯跟之前的相比,多了一個把mockHouses掛載到請求上去的部分。經過測試,不用強制轉換成HttpServletRequest也是可以的。

          對了,我在init()方法和doFilter()方法中都加了打印日志的部分,便于調試。

          房源列表頁面 - houses.jsp

          現在開始編寫我們的JSP頁面,第一個是房源列表。

          編寫房源列表頁面,實際上就是編寫Servlet,只不過它們的HTML和Java內容是反著來的。所以你可以參照原來的HouseServlet中是怎樣輸出HTML的,你就可以把它們拷貝過來,然后把writer.println("")這種去掉,把HTML標簽拿出來,而需要Java代碼的地方就用JSP語法中的<%和%>括起來即可。

          即編寫JSP頁面時,你就可以想象著這是在編寫Servlet的service()方法(除去JSP的聲明,即<%!%>括起來的,和page指令中的import部分以外),只不過HTML內容直接寫,而Java代碼需要<%(或<%=)和%>括起來。

          但實際上,我們仍然可以使用New工具,從而生成通用的JSP模板頁面(工具中可以選擇是HTML 5、HTML 4.01、XHTML等等,我選的是HTML5)。

          我們把這幾個JSP頁面都直接放在WebContent節點下,這樣跟MySecondFilter的映射配置是一致的。

          這里有一個小訣竅,就是寫一部分代碼驗證一部分代碼,不必整個頁面編寫完畢才驗證,當然我們這幾個頁面都比較簡單,也可以全部編寫完畢再驗證。

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          <%@ page import="java.util.List" %>
          <%@ page import="houserenter.entity.House" %>
          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="UTF-8">
          <title>租房網</title>
          </head>
          <body>
          <h1>你好,${param.userName}!歡迎來到租房網! <a href="login.html">退出</a></h1>
          <br><br>
          <%
          	List<House> mockHouses=(List<House>) request.getAttribute("mockHouses");
          	System.out.println(mockHouses);
          %>
          <h6>共找到你感興趣的房源 <%=mockHouses.size() %> 條</h6>
          <ul>
          <%for (House house : mockHouses) { 
          	System.out.println(house); %>
          	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=<%=house.getId() %>"><%=house.getName() %></a></h2></li>
          <%} %>
          </ul>
          </body>
          </html>
          

          需要提一下:

          • 我把編碼格式都改成了UTF-8,此文件一共三處地方。
          • page指令中導入Java類的部分可以在需要的時候編寫,因為開始你也不知道需要什么類啊,后面不能解析類型的變量Eclipse會有提示。
          • 可以看到我用了三種元素:JSP腳本<% %>)、JSP表達式<%=%>)、EL表達式${ }),這回總算清楚它們的基本用法了。
          • 比較奇葩的是for循環部分,盡然可以將前半部分用<% %>括起來、中間部分直接寫HTML代碼、最后一個花括弧也用<% %>括起來。不過也容易理解,這些都要被Servlet容器轉換成Java代碼的。可能看起來有點怪,但你要適應這種風格。
          • JSP表達式可以用在HTML標簽的內容上,還可以用在HTML標簽屬性值的雙引號中。EL表達式也是如此。
          • EL表達式的基本語法是用 ${} 把內容括起來,內容一般是訪問某個對象的屬性,使用點表達式方括號表達式均可,也支持一般的算術運算符、關系運算符、邏輯運算符等等。
          • JSP腳本中的request是JSP的隱式對象,EL表達式中的param是EL中的隱式對象,不過你都可以理解為Servelt容器在轉換成Servlet代碼時幫你定義的對象。param實際上就等價于request.getParameter()方法,也可以理解為param就是一個包括請求中所有參數的Map。
          • 加了一些打印日志的代碼,便于調試。
          • 最后,<a>標簽的跳轉頁面是房源詳情頁面house.jsp,URL中也可以攜帶參數。
          • URL中攜帶的參數與表單中提交的參數,都是使用request.getParameter()來訪問的。
          • request.getAttribute()只能訪問服務端添加的數據,而不是瀏覽器端用戶發送過來的數據。

          驗證

          我們可以一邊開發JSP頁面一邊進行驗證了,Eclispe中啟動Tomcat之后也不用關閉,它會自動檢測JSP頁面和Java代碼的變化,進行重新編譯和發布,不過有時候修改代碼后還是重新發布應用比較踏實。

          先別忘了修改我們的LoginServlet重定向的地址:

          response.sendRedirect("houses.jsp?userName=" + userName);
          

          OK,從瀏覽器中訪問租房網的登錄頁面login.html:

          隨便輸入用戶名和密碼,點擊登錄:

          耶,完全沒有問題!繼續編寫其他兩個JSP頁面。

          房源詳情頁面 - house-details.jsp

          有了前面的分析,相信大家都能夠理解一般的JSP代碼了,那就直接上代碼吧。

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          <%@ page import="java.util.List" %>
          <%@ page import="houserenter.entity.House" %>
          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="UTF-8">
          <title>租房網</title>
          </head>
          <body>
          <h1>你好,${param.userName}!歡迎來到租房網! <a href="login.html">退出</a></h1>
          <br><br>
          <%
          	List<House> mockHouses=(List<House>) request.getAttribute("mockHouses");
          	String houseId=request.getParameter("houseId");
          	House target=null;
          	for (House house : mockHouses) {
          		if (houseId.equals(house.getId())) {
          			target=house;
          			break;
          		}
          	}
          %>	
          <h2><%=target.getName() %><a href="house-form.jsp?userName=${param.userName }&houseId=<%=target.getId() %>">編輯</a></h2>
          <h3><%=target.getDetail() %></h3>
          <h4><a href="houses.jsp?userName=${param.userName }">回到列表</a></h4>
          </body>
          </html>
          

          還是主要用了JSP腳本、JSP表達式和EL表達式三個技術。

          不過,JSP腳本看著似乎有點長。

          房源編輯表單頁面 - house-form.jsp

          還是直接上代碼。

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          <%@ page import="java.util.List" %>
          <%@ page import="houserenter.entity.House" %>
          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="UTF-8">
          <title>租房網</title>
          </head>
          <body>
          <h1>你好,${param.userName}!歡迎來到租房網! <a href="login.html">退出</a></h1>
          <br><br>
          <%
          	List<House> mockHouses=(List<House>) request.getAttribute("mockHouses");
          	String houseId=request.getParameter("houseId");
          	House target=null;
          	for (House house : mockHouses) {
          		if (houseId.equals(house.getId())) {
          			target=house;
          			break;
          		}
          	}
          %>
          <form action="house-form.servlet" method="post">
          <input type="hidden" name="userName" value="${param.userName}"/>
          <input type="hidden" name="houseId" value="<%=target.getId() %>"/>
          <label for="house_name">房源名字:</label><input type="text" id="house_name" name="houseName" value="<%=target.getName() %>" />
          <label for="house_detail">房源詳細信息:</label><input type="text" id="house_detail" name="houseDetail" value="<%=target.getDetail() %>" />
          <input type="submit" value="提交" />
          </form>
          </body>
          </html>
          

          注意,此時表單的提交路徑是:house-form.servlet

          所以,后面編寫HouseFormServlet時,配置其URL映射模式要與此一致。

          處理房源編輯表單的提交 - HouseFormServlet

          無非就是提取表單提交的數據,然后保存到我們的模擬數據中,最后重定向回該房源的詳情頁面。

          package houserenter.servlet;
          import java.io.IOException;
          import java.util.List;
          import javax.servlet.ServletException;
          import javax.servlet.annotation.WebServlet;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import houserenter.entity.House;
          @WebServlet("/house-form.servlet")
          public class HouseFormServlet extends HttpServlet {
          	private static final long serialVersionUID=1L;
          	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          		List<House> mockHouses=(List<House>) request.getAttribute("mockHouses");
          		String houseId=request.getParameter("houseId");
          		House target=null;
          		for (House house : mockHouses) {
          			if (houseId.equals(house.getId())) {
          				target=house;
          				break;
          			}
          		}
          		
          		String houseName=request.getParameter("houseName");
          		target.setName(houseName);
          		
          		String houseDetail=request.getParameter("houseDetail");
          		target.setDetail(houseDetail);
          		
          		String userName=request.getParameter("userName");
          		response.sendRedirect("house-details.jsp?userName=" + userName + "&houseId=" + houseId);
          	}
          }
          

          至此,全部JSP頁面和Servlet代碼已經編寫完畢,大家可以自行驗證,應該沒有問題。

          進一步改進 - include.jsp

          雖然已經完成了全部工作,運行也沒有問題,但是很明顯,三個JSP頁面中開頭的很大一部分都是重復的,這時候JSP中的include指令就排上用場了。

          我們把這部分重復的提取出來,形成一個獨立的JSP文件:

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          <%@ page import="java.util.List" %>
          <%@ page import="houserenter.entity.House" %>
          <!DOCTYPE html>
          <html>
          <head>
          <meta charset="UTF-8">
          <title>租房網</title>
          </head>
          <body>
          <h1>你好,${param.userName}!歡迎來到租房網! <a href="login.html">退出</a></h1>
          <br><br>
          

          然后改造三個JSP頁面,比如房源列表頁面houses.jsp

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          <%@ include file="include.jsp"%>
          <%
          	List<House> mockHouses=(List<House>) request.getAttribute("mockHouses");
          	System.out.println(mockHouses);
          %>
          <h6>共找到你感興趣的房源 <%=mockHouses.size() %> 條</h6>
          <ul>
          <%for (House house : mockHouses) { 
          	System.out.println(house); %>
          	<li><h2><a href="house-details.jsp?userName=${param.userName}&houseId=<%=house.getId() %>"><%=house.getName() %></a></h2></li>
          <%} %>
          </ul>
          </body>
          </html>
          

          直接使用include指令:

          <%@ include file="include.jsp"%>
          

          但是,要注意,房源列表頁面houses.jsp中仍然需要下面的page指令,否則會有中文亂碼:

          <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
          

          實際上,include指令也是由Servlet容器在將JSP頁面生成Servlet代碼的過程中解析,并用包含的JSP頁面的內容替換該指令,完全是解析階段發生的故事。

          最后,我們的租房網的工程結構變成:

          總結

          雖然我們的租房網還不夠完美,但總算比之前純粹使用Servlet的時候干凈清爽多了,頁面結構也比較清晰合理。

          當然,還有很多需要改進的地方,讀者朋友們自己可以思考思考。

          • 養成學、做、思、記的習慣;我寫這些文章,也就是記,鼓勵大家也多記;
          • JSP的本質就是由Servlet/JSP容器轉換成Servlet代碼;
          • Servlet代碼中HTML內容需要writer括起來;而JSP頁面中Java代碼需要<%%>括起來;
          • 加打印日志的代碼,便于調試;
          • 一邊開發、一邊測試/驗證;
          • EL表達式的基本語法是用 ${} 把內容括起來;
          • JSP和EL都有隱式對象,實際上是Servlet/JSP容器生成并傳進來的;
          • 要有演化思維,或迭代思維,或最小可用產品思維;
          • 再次運用消除重復思維,重復的地方總是可以改進的。

          上系統全面的HTML+CSS課程上線了

          0基礎精講,簡單易學,前端開發入門首選課程

          【推薦理由】

          HTML+CSS是學習HTML5的基礎課程,是前端開發的必備技術,無論是PHP、JSP等網站編程語言,都要用到HTML。

          HTML+CSS讓建站更簡單,內容分離布局更靈活,便于維護和修改,尤其是大型網站的制作特別明顯。

          HTML+CSS支持各種瀏覽器,兼容性好,符合web標準規范的發展趨勢,可以使用在廣泛的平臺上。

          HTML+CSS有利于網站的優化,可以被更好的搜索和收錄。

          【課程簡介】

          鄭州HTML5培訓本課程從最基礎的前端認知,工具和插件安裝等開始教起,通俗易懂,步驟詳細,上手簡單,實用性強,非常適合0基礎的人群學習。

          【課程特色】

          金牌師資:藍鷗Html5資深講師

          豐富案例:運用實際的項目講述知識點

          深入淺出:面向零基礎,而又不失去課程的嚴禁和拓展,保證人人可以學會,可以提升自己一個新的高度。

          【講師介紹】

          藍鷗HTML5特級講師

          IT教育行業從業經驗12年,資深前端開發工程師,為人熱情豪邁,熱愛教育行業,擔任全國多所大學的客座講師。

          【我們承諾】

          1.錄制最新課程內容,緊跟HTML+CSS技術發展實時更新知識點;打造全真課堂環境,模擬PPT教學場景與老師手寫電子板書效果。

          2.難點重點集中講解,結合相關案例具體分析,促進對知識點的透徹理解及項目的實戰操作。

          課程目標

          • 了解前端開發職位;

          • 掌握HTML常用標簽以及語義及用法,包括html模板、標簽、表格、表單等等;

          • 掌握常用CSS的基礎知識及布局技巧,能熟練手寫CSS進行網頁布局;

          • 掌握整站規劃基礎。

          鄭州HTML5培訓http://www.lanou3g.com/

          用JSP文件上傳,下載的一些方法,Java實現文件分片上傳、大文件秒傳,大文件如何做斷點續傳?JAVAWEB 文件上傳及下載,JAVA大文件上傳,大文件下載解決方案,JAVA實現文件分片上傳并且斷點續傳,JAVA大文件分片上傳/多線程上傳功能,超大文件上傳和斷點續傳的控件,JAVA實現瀏覽器端大文件分片上傳,JAVA實現大文件上傳,JAVA WEB 實現文件上傳和下載接口功能,

          百度webuploader上傳文件到服務器指定文件夾問題,webuploader上傳文件到服務器指定文件夾問題,JSP上傳文件到服務器指定文件夾問題,JAVA上傳大文件實現源代碼,JAVA上傳大文件實現源碼,JAVA上傳大文件實現代碼,JAVA上傳大文件實現技巧,JAVA上傳大文件實現技術,JAVA上傳大文件實現思路,JAVA上傳大文件實現解決方案,

          前端上傳大文件實現方案,js上傳大文件實現方法,JavaScript上傳大文件實現方法,vue上傳大文件實現方法,前端上傳大文件實現方法,html上傳大文件實現方法,html5上傳大文件實現方法,百度webuploader上傳大文件實現方法,webuploader上傳大文件實現方法,JAVA上傳大文件實現方法,

          網上也搜過相關的解決方案,論壇里面也有網友交流,但是都不太令人滿意,與實際的需求需求也相差太遠。可以說是完全不能滿足公司這邊的項目需求。公司項目這塊實際上是需要一個成熟的商業解決方案。

          大文件上傳的話基本上都是分片來傳,網上很多文章講的不能說亂七八糟只能說完全沒用。

          JAVA的話主要是負責后端的接口,業務邏輯,功能的實現,比如文件初始化,文件分塊,文件塊合并,文件信息的查詢等。

          客戶這個項目跟了很長時間了,大概有2年了。實際上客戶并不在意使用哪種技術,只在乎兩點。

          文件比較大,有50G左右,用戶希望能夠在網頁里面直接上傳,一期的時候我們是直接用的HTML5的API,也就是chrome提供的API來做的,但是上線后用戶反饋不是特別的好用,用戶那邊有些電腦用的是WIN7+IE9,chrome的API在ie9里面不支持。但是用戶系統是支持的,這就把人整的有點不會了。二期的時候我們還是定制開發了,

          前端用了JSP,VUE2,VUE3,后端用了JSP,SpringBoot,IDE用了Eclipse,MyEclipse,因為新項目和老項目都用了兩種IDE。

          用戶要求能夠在網頁上面上傳文件夾,文件夾里面大約有1萬多個文件,有大有小,大的有1G~10G,小的有幾MB,文件夾上傳的時候需要保存層級結構,同時能夠將層級結構信息保存到數據庫中,同時還需要支持文件夾下載,下載下來的文件夾要和上傳的文件夾層級結構一模一樣。客戶每天都會傳輸一些資料,功能這塊使用頻率非常高。

          要求支持斷點續傳,支持進度信息離線存儲,用戶可能傳一半沒有傳完,下班了,明天上班后繼續上傳,電腦晚上到點需要關機,支持加密傳輸,支持國密加密算法SM4,要求支持下載,支持非打包方式下載,瀏覽器要求支持包含IE在內的所有瀏覽器,

          系統環境要求支持信創國產化,比如銀河麒麟,中標麒麟,統信UOS,龍芯,數據庫支持MySQL,Oracle,達夢數據庫,人大金倉,需要提供前端源碼,后端源碼,控件源碼,公司自己的項目,也有自己的產品,后續需要集成使用,

          要求提供7*24小時技術支持服務,提供文檔教程,視頻教程,遠程技術指導,1對1技術支持服務,提供手機,微信,QQ,郵箱,企業微信等聯系方式。導入項目:
          導入到Eclipse:http://www.ncmem.com/doc/view.aspx?id=9da9c7c2b91b40b7b09768eeb282e647
          導入到IDEA:http://www.ncmem.com/doc/view.aspx?id=9fee385dfc0742448b56679420f22162
          springboot統一配置:http://www.ncmem.com/doc/view.aspx?id=7768eec9284b48e3abe08f032f554ea2

          下載示例:

          https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/

          工程

          NOSQL

          NOSQL示例不需要任何配置,可以直接訪問測試

          創建數據表

          選擇對應的數據表腳本,這里以SQL為例

          修改數據庫連接信息

          訪問頁面進行測試

          文件存儲路徑

          up6/upload/年/月/日/guid/filename

          相關問題:
          1.javax.servlet.http.HttpServlet錯誤
          2.項目無法發布到tomcat
          3.md5計算完畢后卡住
          4.服務器找不到config.json文件

          相關參考:

          文件保存位置

          源碼工程文檔:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra

          源碼報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl

          OEM版報價單:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a

          控件源碼下載:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc


          主站蜘蛛池模板: 国产成人无码一区二区三区在线 | 精品无码一区在线观看| 天堂va在线高清一区| 国产成人精品久久一区二区三区| 内射女校花一区二区三区| 视频一区二区三区免费观看| 蜜臀AV无码一区二区三区| 91一区二区在线观看精品| 国产精品美女一区二区视频| 久久精品亚洲一区二区三区浴池| 国产精品一区二区三区99| 国产福利一区二区| 无人码一区二区三区视频| 国产一区二区四区在线观看| 国产综合无码一区二区三区| 国产视频一区二区在线播放| 国产SUV精品一区二区四| 亚洲av无码天堂一区二区三区| 内射女校花一区二区三区| 无码少妇A片一区二区三区| 激情综合丝袜美女一区二区| 精品伦精品一区二区三区视频| 亚洲熟女乱综合一区二区| 国产av夜夜欢一区二区三区| 日韩成人无码一区二区三区| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 久久成人国产精品一区二区| 激情综合丝袜美女一区二区| 无码少妇一区二区| 国产精品无码亚洲一区二区三区 | 视频一区二区精品的福利| 亚洲国产综合精品一区在线播放| 精品一区二区三区免费视频| 无码乱人伦一区二区亚洲一| 久久无码AV一区二区三区| 日韩美女视频一区| 亚洲视频一区在线观看| 国模视频一区二区| 国产乱码伦精品一区二区三区麻豆| 任你躁国语自产一区在| 久久综合一区二区无码|