这份 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 + "https://www.jb51.net/" + 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('\\', 'https://www.jb51.net/'); return absoluteAddress; } public String getEditJSP(HttpServletRequest request) { String uri = request.getRequestURI().replaceAll("admin/\\w+", "index"); uri = uri.replace(request.getContextPath(), ""); return uri; } %>