最近看到一个不错的ios应用“周末-要出发”,觉得整个APP应用的UX挺好,所以对于热门推荐模块进行了模拟实现。
实现步骤:
1.在Eclipse中新建iPhone项目,获得firebug.js文件以及原始的index.html文件;
2.新建Web Project,将之前iPhone项目中js和html文件拷贝过来,这样得到的样式将适合ios系统展示
3.引用dwr.jar和mysql驱动
4.编写java类,以及配置xml(dwr.xml,web.xml)
备注:
a.在数据库中写的图片链接要写http://192.168.1.114:8080/Weekly/IMG/x1.jpg,之前一直写的相对位置,无法显示图片,后来想到是服务器的位置
b.在html页面中通过js调用java代码的话,采用DWR是比较合适的选择,方便,简洁
项目文件夹情况如下:
源代码如下:
mysql数据库,sql:
/*
MySQL Data Transfer
Source Host: localhost
Source Database: iosweb
Target Host: localhost
Target Database: iosweb
Date: 2012-7-26 14:11:25
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for img
-- ----------------------------
CREATE TABLE `img` (
`id` smallint(6) NOT NULL,
`addr` varchar(50) NOT NULL,
`com_top` varchar(50) NOT NULL,
`com_btm_left` varchar(50) NOT NULL,
`com_btm_right` varchar(20) NOT NULL,
`img_description` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records
-- ----------------------------
INSERT INTO `img` VALUES ('0', 'http://192.168.1.114:8080/Weekly/IMG/x1.jpg', '桂峰山高端自驾游2天1晚套餐,避暑仙源独享清幽', '广东 惠州 | 桂峰山度假山庄', '29988元', 'http://192.168.1.114:8080/Weekly/IMG/x1.jpg');
INSERT INTO `img` VALUES ('1', 'http://192.168.1.114:8080/Weekly/IMG/x2.jpg', 'sss', 'sss', 'sss', 'http://192.168.1.114:8080/Weekly/IMG/x2.jpg');
INSERT INTO `img` VALUES ('2', 'http://192.168.1.114:8080/Weekly/IMG/x3.jpg', 'sss', 'sss', 'sss', 'http://192.168.1.114:8080/Weekly/IMG/x3.jpg');
INSERT INTO `img` VALUES ('3', 'http://192.168.1.114:8080/Weekly/IMG/x4.jpg', 'sss', 'sss', 'sss', 'http://192.168.1.114:8080/Weekly/IMG/x4.jpg');
INSERT INTO `img` VALUES ('4', 'http://192.168.1.114:8080/Weekly/IMG/x5.jpg', 'sss', 'sss', 'sss', 'http://192.168.1.114:8080/Weekly/IMG/x5.jpg');
1.index.html
<!-- Based on work by Joe Hewitt : http://www.joehewitt.com/blog/iphone_tips_loo.php --> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<meta name="viewport" content="width=320; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<title>要出发</title>
<link rel="stylesheet" type="text/css" media="screen" href="CSS/styles.css"/>
<script type="text/javascript" src="JS/firebug.js">
</script>
<script type='text/javascript' src='/Weekly/dwr/interface/DWRExample.js'>
</script>
<script type='text/javascript' src='/Weekly/dwr/engine.js'>
</script>
<script type='text/javascript' src='/Weekly/dwr/util.js'>
</script>
<script type="text/javascript" src="JS/main.js">
</script>
</head>
<body>
<div class="container">
<div class="center">
<div class="refresh" id="r1">
下拉即可更新.../松开即可更新.../滚动条+ 加载中...
<br/>
最后更新:
</div>
<div id="contents">
<script type="text/javascript">
show();
</script>
</div>
<button id='addMore' οnclick="show();" value=" ok ">
加载更多
</button>
</div>
</div>
</body>
</html>
2. styles.css
body {
margin: 0;
font-family: Helvetica;
background: #000000;
color: #FFFFFF;
overflow: hidden;
} .container {
position: absolute;
width: 100%;
}
body[orient =
"profile"] .container {
height: 416px;
}
body[orient =
"landscape"] .container {
height: 268px;
} .center {
position: absolute;
top: 0px;
bottom: 0px;
background: #FFFFFF;
width: 100%;
}
body[orient =
"landscape"] .center {
top: 0px;
bottom: 0px;
width: 100%;
} .item {
border-bottom: 1px solid #E0E0E0;
background: #ffffff;
color: #000000;
padding: 2%;
height: 210px;
} #addMore {
background-color: #ffffff;
border-width: 0;
height: 30px;
width: 100%;
font-size: 20px;
} img {
width: 100%;
height: 150px;
} .refresh {
padding: 10px 0;
width: 100%;
height: 20px;
font-size: 10px;
font-weight: bold;
text-align: center;
text-shadow: #3F4E63 0px -1px 1px;
background: #d3d5d8;
display: none;
} .comments_top {
margin-top:10px;
word-break:keep-all;/* 不换行 */
white-space:nowrap;/* 不换行 */
overflow:hidden;/* 内容超出宽度时隐藏超出部分的内容 */
text-overflow:ellipsis;
} .comments_bottom {
margin-top: 10px;
} .comments_bottom_left {
float: left;
margin-bottom:0px;
} .comments_bottom_right {
float: right;
color: #F6680C;
margin-bottom:0px;
}
3.firebug.js
if (!("console" in window) || !("firebug" in console)) {
(function()
{
window.console =
{
firebug: "ibug0.1",
log: function()
{
logFormatted(arguments, "");
},
debug: function()
{
logFormatted(arguments, "debug");
},
info: function()
{
logFormatted(arguments, "info");
},
warn: function()
{
logFormatted(arguments, "warning");
},
error: function()
{
logFormatted(arguments, "error");
},
assert: function(truth, message)
{
if (!truth)
{
var args = [];
for (var i = 1; i < arguments.length; ++i)
args.push(arguments[i]);
logFormatted(args.length ? args : ["Assertion Failure"], "error");
throw message ? message : "Assertion Failure";
}
},
dir: function(object)
{
var html = [];
var pairs = [];
for (var name in object)
{
try
{
pairs.push([name, object[name]]);
}
catch (exc)
{
}
}
pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1; });
html.push('<table>');
for (var i = 0; i < pairs.length; ++i)
{
var name = pairs[i][0], value = pairs[i][1];
html.push('<tr>',
'<td class="propertyNameCell"><span class="propertyName">',
escapeHTML(name), '</span></td>', '<td><span class="propertyValue">');
appendObject(value, html);
html.push('</span></td></tr>');
}
html.push('</table>');
logRow(html, "dir");
},
dirxml: function(node)
{
var html = [];
appendNode(node, html);
logRow(html, "dirxml");
},
group: function()
{
logRow(arguments, "group", pushGroup);
},
groupEnd: function()
{
logRow(arguments, "", popGroup);
},
time: function(name)
{
timeMap[name] = (new Date()).getTime();
},
timeEnd: function(name)
{
if (name in timeMap)
{
var delta = (new Date()).getTime() - timeMap[name];
logFormatted([name+ ":", delta+"ms"]);
delete timeMap[name];
}
},
count: function()
{
this.warn(["count() not supported."]);
},
trace: function()
{
this.warn(["trace() not supported."]);
},
profile: function()
{
this.warn(["profile() not supported."]);
},
profileEnd: function()
{
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
$: function(id)
{
return document.getElementById(id);
},
$$: function(selector)
{
// XXXjoe Make this into getElementsBySelector
return document.getElementsByTagName(selector);
},
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
onError: function(msg, href, lineNo)
{
var html = [];
var lastSlash = href.lastIndexOf("/");
var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
html.push(
msg, ' (line ', lineNo, ')'
);
logRow(html, "error");
},
command: function(text)
{
with (console)
{
try {
var result = eval(text);
console.log('return value: '+ result);
}
catch (exc)
{
console.onError(exc.message, exc.sourceId+"", exc.line);
}
}
},
handshake: function(callback)
{
sendMessage = callback;
for (var i = 0; i < queue.length; ++i)
sendMessage(queue[i]);
}
};
// ********************************************************************************************
var timeMap = {};
var queue = [];
function init()
{
//var iframe = document.createElement("iframe");
//document.body.appendChild(iframe);
//iframe.src = "http://" + ibugHost + "/iphone";
setInterval(checkComand, 1000);
}
function checkComand()
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "/iphone-command");
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
var text = xmlhttp.responseText;
if(text != "" && typeof(text) != "undefined" && text != null)
{
console.command(text);
}
}
}
xmlhttp.send(null)
}
function sendMessage(message)
{
// Until we get a handshake from the iframe, queue messages for delivery
//queue.push(message);
var request = new XMLHttpRequest();
request.open("POST", "/iphone");
request.send(message);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
function appendText(object, html)
{
html.push(escapeHTML(objectToString(object)));
}
function appendNull(object, html)
{
html.push(objectToString(object));
}
function appendString(object, html)
{
html.push(objectToString(object));
}
function appendInteger(object, html)
{
html.push(objectToString(object));
}
function appendFloat(object, html)
{
html.push(objectToString(object));
}
function appendFunction(object, html)
{
var reName = /function ?(.*?)\(/;
var m = reName.exec(objectToString(object));
var name = m ? m[1] : "function";
html.push(name, '()');
}
function appendArray(object, html)
{
html.push('[');
for (var i = 0; i < object.length; ++i)
{
if (i > 0)
html.push(',');
appendObject(object[i], html);
}
html.push(']');
}
function appendObject(object, html)
{
try
{
if (object == undefined)
appendNull("undefined", html);
else if (object == null)
appendNull("null", html);
else if (typeof object == "string")
appendString(object, html);
else if (typeof object == "number")
appendInteger(object, html);
else if (object.nodeType == 1)
appendSelector(object, html);
else if (object == window || object == document)
appendObjectFormatted(object, html);
else if (typeof(object.length) == "number")
appendArray(object, html);
else if (typeof object == "object")
appendObjectFormatted(object, html);
else if (typeof object == "function")
appendFunction(object, html);
else
appendText(object, html);
}
catch (exc)
{
}
}
function appendObjectFormatted(object, html)
{
var text = objectToString(object);
var reObject = /\[object (.*?)\]/;
var m = reObject.exec(text);
html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
}
function appendSelector(object, html)
{
html.push('<span class="objectBox-selector">');
html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
if (object.id)
html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
if (object.className)
html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
html.push('</span>');
}
function appendNode(node, html)
{
if (node.nodeType == 1)
{
html.push(
'<div class="objectBox-element">',
'<<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
for (var i = 0; i < node.attributes.length; ++i)
{
var attr = node.attributes[i];
if (!attr.specified)
continue;
html.push(' <span class="nodeName">', attr.nodeName.toLowerCase(),
'</span>="<span class="nodeValue">', escapeHTML(attr.nodeValue),
'</span>"')
}
if (node.firstChild)
{
html.push('></div><div class="nodeChildren">');
for (var child = node.firstChild; child; child = child.nextSibling)
appendNode(child, html);
html.push('</div><div class="objectBox-element"></<span class="nodeTag">',
node.nodeName.toLowerCase(), '></span></div>');
}
else
html.push('/></div>');
}
else if (node.nodeType == 3)
{
html.push('<div class="nodeText">', escapeHTML(node.nodeValue),
'</div>');
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
function logRow(message, className, handler)
{
sendMessage(className + ": " + message.join(""));
}
function logFormatted(objects, className)
{
var html = [];
var format = objects[0];
var objIndex = 0;
if (typeof(format) != "string")
{
format = "";
objIndex = -1;
}
var parts = parseFormat(format);
for (var i = 0; i < parts.length; ++i)
{
var part = parts[i];
if (part && typeof(part) == "object")
{
var object = objects[++objIndex];
part.appender(object, html);
}
else
appendText(part, html);
}
for (var i = objIndex+1; i < objects.length; ++i)
{
appendText(" ", html);
var object = objects[i];
if (typeof(object) == "string")
appendText(object, html);
else
appendObject(object, html);
}
if (!className && html.length == 1 && typeof(objects[0]) == "string")
className = "text";
logRow(html, className);
}
function parseFormat(format)
{
var parts = [];
var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};
for (var m = reg.exec(format); m; m = reg.exec(format))
{
var type = m[8] ? m[8] : m[5];
var appender = type in appenderMap ? appenderMap[type] : appendObject;
var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
parts.push({appender: appender, precision: precision});
format = format.substr(m.index+m[0].length);
}
parts.push(format);
return parts;
}
function escapeHTML(value)
{
return value;
function replaceChars(ch)
{
switch (ch)
{
case "<":
return "<";
case ">":
return ">";
case "&":
return "&";
case "'":
return "'";
case '"':
return """;
}
return "?";
};
return String(value).replace(/[<>&"']/g, replaceChars);
}
function objectToString(object)
{
try
{
return object+"";
}
catch (exc)
{
return null;
}
}
setTimeout(init, 0);
})();
}
4.main.js
var num = 0; // 当前加载次数
var L = 0; // 第一次用掉的Num
var R = 0; // 当前剩下的Num
var allData = 0; // 最后一次的Num
var step = 0;
var flag = true;
function show(){
//display list data
DWRExample.getList(call);
}
function call(data){
var content = document.getElementById("contents").innerHTML;
if (data) {
if (num == 0) {
allData = data.length;
L = 0;
step = (allData < 2) ? allData : 2;
R = L + step;
num++;
}
else {
if ((allData - R) > 0) {
L = R;
step = ((allData - L) < 2) ? (allData - L) : 2;
R = L + step;
num++;
}
else {
flag = false;
}
}
if (flag) {
for (var i = L; i < R; i++) {
//alert(data[i].name);
var str = "<div class=item><a href='";
str += data[i].imgDescription;
str += "'><img src='";
str += data[i].addr;
str += "'></img></a><div class=comments_top>";
str += data[i].comTop;
str += "</div><div class=comments_bottom><div class=comments_bottom_left>";
str += data[i].comBtmLeft;
str += "</div><div class=comments_bottom_right>";
str += data[i].comBtmRight;
str += "</div></div></div>";
content += str;
}
}
else {
alert("亲,所有数据都加载完咯!*^_^*");
}
DWRUtil.setValue("contents", content);
}
}
addEventListener("load", function(){
setTimeout(updateLayout, 0);
}, false);
var currentWidth = 0;
function updateLayout(){
if (window.innerWidth != currentWidth) {
currentWidth = window.innerWidth;
var orient = currentWidth == 320 ? "profile" : "landscape";
document.body.setAttribute("orient", orient);
setTimeout(function(){
window.scrollTo(0, 1);
}, 100);
}
}
setInterval(updateLayout, 1400);
console.info('iPhone logging initialized');
5.dwr.xml
<?xml version="1.0" encoding="utf-8"?>
<dwr>
<allow>
<convert converter="bean" match="com.DemoBean"/>
<create creator="new" javascript="DWRExample" class="com.DWRExample" scope="session">
<include method="getList"/>
</create>
</allow>
</dwr>
6.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- DWR2.0 -->
<servlet>
<servlet-name>dwrInvoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>classes</param-name>
<param-value>java.lang.Object</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwrInvoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
</web-app>
6. DemoBean.java
package com;
import java.io.Serializable;
public class DemoBean
implements Serializable
{
public DemoBean()
{
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getAddr()
{
return addr;
}
public void setAddr(String addr)
{
this.addr = addr;
}
public String getComTop()
{
return comTop;
}
public void setComTop(String comTop)
{
this.comTop = comTop;
}
public String getComBtmLeft()
{
return comBtmLeft;
}
public void setComBtmLeft(String comBtmLeft)
{
this.comBtmLeft = comBtmLeft;
}
public String getComBtmRight()
{
return comBtmRight;
}
public void setComBtmRight(String comBtmRight)
{
this.comBtmRight = comBtmRight;
}
public String getImgDescription()
{
return imgDescription;
}
public void setImgDescription(String imgDescription)
{
this.imgDescription = imgDescription;
}
private int id;
private String addr;
private String comTop;
private String comBtmLeft;
private String comBtmRight;
private String imgDescription;
}
7.DWRExample.java
package com;
import java.io.Serializable;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
// Referenced classes of package com:
// DemoBean
public class DWRExample
implements Serializable
{
public DWRExample()
{
}
public List getList()
{
List imgList;
String sql;
String driver;
String url;
String user;
String password;
Statement stmt;
ResultSet rs;
Connection conn;
imgList = new ArrayList();
DemoBean img = null;
sql = "select * from img";
driver = "com.mysql.jdbc.Driver";
url = "jdbc:MySQL://127.0.0.1:3306/iosweb";
user = "root";
password = "root";
stmt = null;
rs = null;
conn = null;
try
{
Class.forName(driver);
conn = DriverManager.getConnection(url, user, password);
if(!conn.isClosed())
{
stmt = conn.createStatement();
img = new DemoBean();
for(rs = stmt.executeQuery(sql);
rs.next();
imgList.add(img))
{
img = new DemoBean();
img.setId(Integer.parseInt(rs.getString("id")));
img.setAddr(rs.getString("addr"));
img.setComTop(rs.getString("com_top"));
img.setComBtmLeft(rs.getString("com_btm_left"));
img.setComBtmRight(rs.getString("com_btm_right"));
img.setImgDescription(rs.getString("img_description"));
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
try
{
rs.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
stmt.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
conn.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
rs.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
stmt.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
conn.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
rs.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
stmt.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
try
{
conn.close();
}
catch(SQLException e)
{
e.printStackTrace();
}
return imgList;
}
public boolean checkUser(String name)
{
return "xy".equals(name);
}
}