TML5是移动互联网的未来吗?
自2010年乔布斯公开支持并在iOS禁止Flash后,在多数开发者心中,这开始变成一个肯定的答案。
2010年到2011年,HTML5概念被热炒,受到追捧,甚至不少人预言HTML5应用将会替代原生app。但或许是当初被捧得太高,而不论是生态环境还是技术支持都远远算不上成熟,HTML5游戏在短暂热捧之后遭遇诸多问题,随后开始陷入冰谷,当初使用HTML5开发游戏的团队纷纷转型——HTML5或许将是未来,但现在谈论还为时过早。
在被遗忘一段时间之后,现在,一些专注于游戏领域的HTML5引擎服务提供商正在重整旗鼓(详见今日推送的第二篇文章),这让我们不由再次回头审视HTML5游戏走过的整个路程,并开始思考一个问题:在HTML5那条通往“未来”的遥远道路上,它正站在一个什么样的位置上?
■过去
2010年4月,苹果公司宣布禁止FlashPlayer登陆iOS系统,鼓励开发者使用HTML5技术,这一举动引起了轩然大波,乔布斯甚至为此撰写了一篇长文《关于Flash的几点思考》进行回应。当年十月,Zynga收购了HTML5游戏引擎开发商Dextrose,并在随后发布了第一款HTML5游戏《MafiaWarsAtlanticCity》。
从2011年开始,HTML5的概念开始火爆,在这一年,诸多大厂纷纷出击这一领域进行布局,MOTO投资了HTML5游戏公司Moblyng,迪士尼收购了HTML5游戏引擎公司RocketPack。
Facebook社交游戏开发商Wooga也在当年宣布进军HTML5和iOS游戏领域。
在同一年,Unity确认支持HTML5,Facebook收购HTML5技术团队Strobe,将自身在移动端的发力重心放在HTML5上。同年,手游大厂EA、Popcap、Gameloft也相继发布了自己的HTML5游戏。
在2011年底,还有一件重要的事情,Adobe宣布停止在Android系统更新FlashPlayer,并推荐开发者使用HTML5技术开发移动Web应用。
就在看起来形势一片大好HTML5概念火热的时候,哀歌从2012年开始唱响。
在2012年开年之际,此前MOTO投资的HTML5游戏开发商Moblyng倒闭是第一个音符,随后在六月,Wooga宣布停止开发HTML5游戏,他们曾经推出一款HTML5游戏《MagicLand:Island》,但是玩家玩这个游戏的总次数只有130万次,留存率仅5%,相比之下,他们在iOS平台推出的《DiamondDash》则获得了1800万次的下载。
为这支哀歌谱下强音的是Facebook的失败。在2012年9月,扎克伯格在接受采访时表示:“Facebook曾经错误地将赌注押在了HTML5上,这是我们最大的战略错误,致使我们错失了移动市场的发展良机。”
在那之后,曾经被捧上高位打上未来标签的HTML5技术在移动端狠狠摔落,HTML5开始淡出视野。
总结下来,HTML5在移动游戏领域所遭遇的困境,主要是由于四个原因:
1、技术不成熟,开发生态不完整
2、没有合适的载体,浏览器渲染性能低下
3、没有成熟的生态环境(渠道,运营商)
4、受制于网络环境
这些原因最终造成了游戏功能和表现受限,体验大打折扣。
在2013年底,下一代JavaScript标准规范ES6草案锁定并正式发布。
■现在
目前HTML5的框架和库都普遍偏于Web应用的制作,专注于游戏的偏少,比较流行的HTML5框架包括CreateJS,JQuery,AngularJS和Node.js,专注于HTML5游戏的引擎有Impact、Phaser、Pixi、Createjs、EaselJSPhaser、Turbulenz、GameClosure、Coco2d-HTML5和Egret等。
现在主流网站几乎全部支持HTML5标准,几乎所有流行的网站都采用了HTML5技术。但是在移动设备上,还尚未出现非常成熟的HTML5应用或游戏,这一市场还在刚刚起步。游戏方面,此前有一二三国、修仙三国、三国喵喵传等游戏,而目前,墨麟、游戏谷、光年互动等开发商正在开发HTML5游戏。
正在发生的另外一些事情:
1.各浏览器对HTML5标准化的支持正在慢慢趋于一致
2.硬件的变革正在不断推动采用HTML5技术制作的复杂应用和游戏的用户体验的快速提升
3.Web游戏类型在3G/4G网络下的数据发送接收速度正在变得相对高效,但目前国内总体网络质量仍不乐观
4.逐渐涌现出的HTML5游戏引擎和制作工具,开始降低H5游戏制作成本,并提高游戏开发效率
5.混生应用出现,上层使用h5开发,底层使用c++渲染,性能得到很大提升,这种方式是当前阶段的主流
6.一些巨头正在尝试引领这个市场,腾讯的手机QQ空间的安卓版应用,在前段时间将“玩吧”菜单放置在了底部菜单栏的一级入口;在玩吧中,现在已经上线了不少HTML5游戏,不仅有休闲游戏,也有一些卡牌类的中重度游戏,同时在安装QQ空间首次登录时,会自动进入一个名为“让童年飞”的HTML5休闲游戏,腾讯正在尝试引导用户尝试这些HTML5游戏,不过总体来说,内容还处于匮乏阶段,玩吧目前仅提供13款游戏;此外还有百度轻应用等。
看起来一切正在往前有序推进,不过站在游戏开发者角度来说又是什么看法?
在一些开发者看来,HTML5游戏开发快、易调试、跨平台、推广成本更低的特点,或许会是其优势所在,但是问题的核心在于如果不能在游戏体验上给予玩家更多好处,那么就没有太多的理由去看好,基于这点才会有市场,别的都是业内臆想。
而对于游戏玩家来说,内容才是永远的核心。
■未来
HTML5的成熟条件是什么?
目前的发展情况来看,HTML5将成为未来5-10年内移动互联网领域的主宰者,也由此可以看出HTML5的未来十分光明,HTML5开发这项技术也是值得我们去学习的。HTML5培训专家分享Web前端工程师需掌握的基础知识。
1、html+CSS,精通掌握HTML5的应用,掌握CSS在开发中的使用,学会页面标准化布局技术
2、JavaScript,并不是所有的网页都必须有js,但是如果想要实现一些超炫的功能和界面的时候,这就必须使用js了。但是现在不管是企业主本身还是用户都会对JavaScript偏爱一些,所以作为一名web前端工程师这是你的必备课;
3、简单的图片、视频编辑工具,例如:Photoshop、flash。掌握这些最基本的就是可以提高自身的工作效率,试想如果这些你不会的话,你事事还要找这些相关的负责人哪怕是一点小事,那你的时间真的就全浪费在了沟通上了。
4、浏览器兼容问题,懂web标准,熟练手写xhtmlcss3并符合符合w3c标准。代码能兼容主流浏览器Firfox,Chrome、Safari、IE、Opera。虽然IE6很多都不兼容,但现在还利用的人还是有的。
5、熟悉一门后台编程语言,ASP、PHP、jsp都是可以的。
渥瑞达HTML5培训学校作为中国领先的HTML5培训企业,是国内唯一具备软件开发背景的企业级培训,为许多优秀的IT企业输送了大量的人才,而HTML5将作为未来很长一段时间内国内最热门的技术,也是值得你来为人生投资的,如果你希望获得未来人生的加码,不妨考虑参加渥瑞达HTML5培训,为就业打下坚实的基础。
本系列文章旨在记录和总结自己在Java Web开发之路上的知识点、经验、问题和思考,希望能帮助更多(Java)码农和想成为(Java)码农的人。
上篇文章介绍了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页面代替,咱就命名为:
另外,因为涉及到一个房源编辑的表单,所以需要一个Servlet来处理表单的提交,就叫HouseFormServlet吧。
还有一个要提的是HouseServlet初始化了一些模拟数据,那这部分应该放在哪呢?因为一个JSP页面就相当于一个Servlet,所以原来的HouseServlet现在要改造成三个JSP页面,感觉模拟数据放在哪个JSP页面都不太合适,因为三个JSP页面都要访问同一份模拟数据才行。
于是问题变为:如何在多个JSP页面之间共享访问同一份数据?我先想到的是能不能在一个Filter中初始化模拟数据,然后让它拦截到这三个JSP页面的请求,然后在请求中使用setAttribute()方法将模拟数据挂上去,最后在JSP页面中使用请求的getAttribute()方法取出来。
好了,既然思路有了,那我们就大刀阔斧的干吧。
不过我们可以把之前的代码都保留着,另外编写新添加的JSP页面和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()方法中都加了打印日志的部分,便于调试。
现在开始编写我们的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>
需要提一下:
我们可以一边开发JSP页面一边进行验证了,Eclispe中启动Tomcat之后也不用关闭,它会自动检测JSP页面和Java代码的变化,进行重新编译和发布,不过有时候修改代码后还是重新发布应用比较踏实。
先别忘了修改我们的LoginServlet重定向的地址:
response.sendRedirect("houses.jsp?userName=" + userName);
OK,从浏览器中访问租房网的登录页面login.html:
随便输入用户名和密码,点击登录:
耶,完全没有问题!继续编写其他两个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脚本看着似乎有点长。
还是直接上代码。
<%@ 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映射模式要与此一致。
无非就是提取表单提交的数据,然后保存到我们的模拟数据中,最后重定向回该房源的详情页面。
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代码已经编写完毕,大家可以自行验证,应该没有问题。
虽然已经完成了全部工作,运行也没有问题,但是很明显,三个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的时候干净清爽多了,页面结构也比较清晰合理。
当然,还有很多需要改进的地方,读者朋友们自己可以思考思考。
*请认真填写需求信息,我们会在24小时内与您取得联系。