前言
实现一个简易的页面编辑器是大家在学习jsp的时候经常会遇到的一个需求,发现网上这方便的资料不多,所以想着自己总结下,本文详细介绍了jsp简易页面编辑器的实现方法,下面话不多说,来一起看看详细的介绍:
需求
提供一页面,放置“帮助”、“版权”文字内容,特点:静态页面,无须读数据库,只是应付字眼上频繁的修改;没有复杂的交互,无须 javascript;没有图片,不需要文件上传。
给出的方案:提供一页面和简易的后台管理,功能单一,只是编辑页面(只是修改字体、大小、粗体、斜体等的功能)。
实现思路:纯 jsp 展示,管理界面用 http basic 登入,通过一个 js 写成 html 编辑器修改页面内容。直接修改服务器磁盘文件。
界面如下,右图是后台编辑。
值得一提的是,tomcat 7 下 jsp 默认的 java 语法仍旧是 1.6 的。在 jsp 里面嵌入 java 1.7 特性的代码会抛出“resource specification not allowed here for source level below 1.7”的异常。于是需要修改 tomcat/conf/web.xml 里面的配置文件,找到 <servlet> 节点( <servlet-name>jsp</servlet-name> 的才是),加入下面最后两个 init-param 节点部分。注意是 <servlet-name>jsp</servlet-name> 节点才可以,不是 default 节点(很相似)。
<servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.jspservlet</servlet-class> <init-param> <param-name>fork</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>xpoweredby</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>compilersourcevm</param-name> <param-value>1.7</param-value> </init-param> <init-param> <param-name>compilertargetvm</param-name> <param-value>1.7</param-value> </init-param> <load-on-startup>3</load-on-startup> </servlet>
访问的 jsp 其实只有两个 /index.jsp 和 /admin/index.jsp,分别是静态页面和后台编辑页面。/admin/action.jsp 用于接收保存的 action,数据由表单 post 过来。functions.jsp 就是全部的业务逻辑代码,通过 %@include file="functions.jsp"% ,它不能单独给外界 url 访问。
我们先看看 /index.jsp。
<%@page pageencoding="utf-8"%>
<html>
<head>
<title>帮助</title>
<meta charset="utf-8" />
<!--宽度 320px -->
<meta name="viewport" content="width=320,user-scalable=0,initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0" />
<style>
html {
font-size: 15px;
}
body {
padding: 0;
margin: 0 auto;
max-width: 600px;
-webkit-font-smoothing: antialiased;
font-family: "microsoft yahei", "ff-tisa-web-pro-1", "ff-tisa-web-pro-2",
"lucida grande", "hiragino sans gb", "hiragino sans gb w3", arial;
background-color: #ebebeb;
}
h1 {
text-align: center;
font-size: 1.5rem;
letter-spacing: 2px;
color: #864c24;
border-bottom: #e0c494 solid 1px;
padding: 2% 0;
}
h2 {
font-size: 1rem;
letter-spacing: 1px;
color: #4c4c4c;
padding-bottom:0;
margin: 0;
}
p {
text-align: justify;
font-size: 1rem;
color: #818181;
margin: 1% 0;
margin-top:0;
}
ol {
padding: 0;
margin: 0;
}
ol {
}
ol>li>:first-child {
/* make firefox put the list marker inside */
/* https://bugzilla.mozilla.org/show_bug.cgi?id=36854 "if list-style-position is inside, bullet takes own line" */
display: inline;
}
ol>li>:first-child:after {
/* add the margin that was lost w/ display: inline */
/* firefox 10 displays this as block */
/* safari 5.1.2 and chrome 17.0.963.56 don't */
content: "";
display: block;
}
li {
padding: 5% 2%;
list-style-position: inside;
border-bottom: 1px solid #dddddb;
}
.text {
color: #a8a8a8;
font-size: 1rem;
font-weight: bold;
padding: 2%;
}
</style>
</head>
<body>
<!-- editable area|start --> <h1>帮助</h1>
<div class="text">常见问题</div>
<ol>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
<li>
<h2>power tv的资费是怎样收取的?</h2>
<p>12元power tv手机电视包月,产品代码88888888,12元/月;省内用户省内使用配送3g/月定向流量,流量仅用于使用power tv,超过定向流量部分按标准资费收取; </p>
</li>
</ol>
<!-- editable area|end -->
</body>
</html>
这份 jsp 与一般 jsp 并无特异,只不过大家有没有留意到两段注释: <!-- editable area|start --> 和 <!-- editable area|end --> ——这就是我们约定的“可编辑”范围。当然,使用自定义的 html tag 也可以,只要定义了一个范围即可。一份网页,无非是 html。对于其中欲编辑的东西,我们定义一个范围指明哪些地方需要编辑,就可以了。至于为什么不让全部的页面可以编辑?是因为我们不想用户对页面其它部分进行编辑,万一修改了的关键地方造成了错误,那可不好。
好了,怎么让这个 /index.jsp 编辑呢?就是利用 java 读取磁盘的方法来做的。在这个之前,得先登录到 /admin/index.jsp。这里我们通过 http basic authorization 来做用户认证,无须数据库。如果需要修改 账号密码,打开 admin/functions.jsp,编辑头部分即可:
<%! public static final string userid = "admin", pwd = "123123"; .... %>
不过笔者调试 http basic authorization 遇到了个小问题,就是浏览器弹出的对话框,不知怎么修改其中的提示文字,试过几种方法,要么不显示,要么乱码。如果知道的童鞋还请告知一二!
action.jsp 也要作认证的限制,不然等于是个漏洞可以让别人 post 任何数据到页面。
<%@page pageencoding="utf-8"%>
<%@include file="functions.jsp"%>
<%
if (checkauth(request.getheader("authorization"), userid, pwd)) {
request.setcharacterencoding("utf-8");
if (request.getmethod().equalsignorecase("post")) {
string contentbody = request.getparameter("contentbody"), path = mappath(geteditjsp(request));
system.out.println("path:::" + path);
save_jsp_filecontent(path, contentbody);
out.println("<script>alert('修改成功!');window.location = document.referrer;</script>");
} else {
out.println("method error");
}
} else {
%>
<html>
<body>
非法登录!
</body>
</html>
<%
}
%>
修改下页面,点击保存就可以修改页面了。
至于 html 如何编辑?这个答案想必大家都清楚,使用 html 可视化编辑器即可,在线的哦,而不是什么 dreamweaver、frontpage、vs web 之类啦。老人们用过的就是有 fckeditror 呀、tinymce editor,近几年好像喜欢用国产了,我就不知道了。现在这个用的是我自己写,功能比较单一的。
核心逻辑是通过下面的代码搞定的。
<%@page pageencoding="utf-8" import="sun.misc.base64decoder, java.io.*"%>
<%!
public static final string userid = "admin", pwd = "86006966";
// 检查 http basic 认证
/**
* 是否空字符串
*
* @param str
* @return
*/
public static boolean isemptystring(string str) {
return str == null || str.trim().isempty();
}
/**
* 是否不合法的数组
*
* @param arr
* @return
*/
public static boolean isbadarray(string[] arr) {
return arr == null || arr.length != 2;
}
/**
*
* @param authorization
* 认证后每次http请求都会附带上 authorization 头信息
* @param username
* 用户名
* @param password
* 密码
* @return true = 认证成功/ false = 需要认证
*/
public static boolean checkauth(string authorization, string username, string password) {
if (isemptystring(authorization))
return false;
string[] basicarray = authorization.split("\s+");
if (isbadarray(basicarray))
return false;
string idpass = null;
try {
byte[] buf = new base64decoder().decodebuffer(basicarray[1]);
idpass = new string(buf, "utf-8");
} catch (ioexception e) {
e.printstacktrace();
return false;
}
if (isemptystring(idpass))
return false;
string[] idpassarray = idpass.split(":");
if (isbadarray(idpassarray))
return false;
return username.equalsignorecase(idpassarray[0]) && password.equalsignorecase(idpassarray[1]);
}
/**
* 可编辑标识开始
*/
private final static string starttoken = "<!-- editable area|start -->";
/**
* 可编辑标识结束
*/
private final static string endtoken = "<!-- editable area|end -->";
/**
* 根据 页面中可编辑区域之标识,取出来。
*
* @param fullfilepath
* 完整的 jsp 文件路径
* @return 可编辑内容
* @throws ioexception
*/
public static string read_jsp_filecontent(string fullfilepath) throws ioexception {
string jsp_filecontent = readfile(fullfilepath);
int start = jsp_filecontent.indexof(starttoken), end = jsp_filecontent.indexof(endtoken);
try {
jsp_filecontent = jsp_filecontent.substring(start + starttoken.length(), end);
} catch (stringindexoutofboundsexception e) {
jsp_filecontent = null;
string msg = "页面文件" + fullfilepath + "中没有标记可编辑区域之标识。请参考:" + starttoken + "/" + endtoken;
throw new ioexception(msg);
}
return jsp_filecontent;
}
/**
* 请求附带文件参数,将其转换真实的磁盘文件路径
*
* @param rawfullfilepath
* url 提交过来的磁盘文件路径,可能未包含文件名或加了很多 url 参数
* @return 完整的磁盘文件路径
*/
static string getfullpathbyrequesturl(string rawfullfilepath) {
if (rawfullfilepath.indexof(".jsp") == -1)
rawfullfilepath += "/index.jsp"; // 加上 扩展名
if (rawfullfilepath.indexof("?") != -1) // 去掉 url 参数
rawfullfilepath = rawfullfilepath.replaceall("\?.*$", "");
return rawfullfilepath;
}
/**
* 保存要修改的页面
*
* @param rawfullfilepath
* 真实的磁盘文件路径
* @param newcontent
* 新提交的内容
* @throws ioexception
*/
public static void save_jsp_filecontent(string rawfullfilepath, string newcontent) throws ioexception {
string fullfilepath = getfullpathbyrequesturl(rawfullfilepath); // 真实的磁盘文件路径
string jsp_filecontent = readfile(fullfilepath), todel_filecontent = read_jsp_filecontent(fullfilepath);// 读取旧内容
//system.out.println(jsp_filecontent);
//system.out.println(todel_filecontent);
if (todel_filecontent != null) {
jsp_filecontent = jsp_filecontent.replace(todel_filecontent, newcontent);
save2file(fullfilepath, jsp_filecontent); // 保存新内容
} else {
throw new ioexception("页面文件中没有标记可编辑区域之标识。请参考: starttoken/endtpoken");
}
}
/**
* 读取文件
*
* @param filename
* @return
* @throws ioexception
*/
public static string readfile(string filename) throws ioexception {
file file = new file(filename);
if (!file.exists())
throw new filenotfoundexception(filename + " 不存在!");
try (fileinputstream is = new fileinputstream(file);) {
string line = null;
stringbuilder result = new stringbuilder();
try (inputstreamreader isreader = new inputstreamreader(is, "utf-8");
bufferedreader reader = new bufferedreader(isreader);) {
while ((line = reader.readline()) != null) {
result.append(line);
result.append('n');
}
} catch (ioexception e) {
system.err.println(e);
}
return result.tostring();
} catch (ioexception e) {
system.err.println("讀取文件流出錯!" + filename);
throw e;
}
}
/**
* 写文件不能用 filewriter,原因是会中文乱码
*
* @param filename
* @param content
* @throws ioexception
*/
public static void save2file(string filename, string content) throws ioexception {
try (fileoutputstream out = new fileoutputstream(filename);
// outputstreramwriter将输出的字符流转化为字节流输出(字符流已带缓冲)
outputstreamwriter writer = new outputstreamwriter(out, "utf8");) {
writer.write(content);
} catch (ioexception e) {
system.err.println("写入文件" + filename + "失败");
throw e;
}
}
/**
* 输入一个相对地址,补充成为绝对地址 相对地址转换为绝对地址,并转换斜杠
*
* @param relativepath
* 相对地址
* @return 绝对地址
*/
public string mappath(string relativepath) {
string absoluteaddress = getservletcontext().getrealpath(relativepath); // 绝对地址
if (absoluteaddress != null)
absoluteaddress = absoluteaddress.replace('\', '/');
return absoluteaddress;
}
public string geteditjsp(httpservletrequest request) {
string uri = request.getrequesturi().replaceall("admin/\w+", "index");
uri = uri.replace(request.getcontextpath(), "");
return uri;
}
%>
用户凭账号密码登入简易的后台,通过可视化编辑器即可修改页面内容,立刻修改,立刻产生效果,简单快捷——把页面开放出来允许自主编辑这样会提高效率——减少来回修改的次数。
完整源码下载:http://xiazai.jb51.net/201707/yuanma/jsp-page(jb51.net).rar
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对硕编程的支持。
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!