这是本次项目的最后一个问题了,把这个问题解决了,项目就彻底竣工了。先说说要达到的效果:点击一个关键字,使用URL重写传值给Servlet,然后从数据库中查出所有包含这个关键字的文章。
然而在JSP中我们点击这样一个超级链接:http://localhost:8080/wwwroot/tagservlet?tag=数据库
可是这样传递的值我们在Servlet中是没法获取到的,我们需要对这里的汉字进行URL编码,这样我们才能够在Servlet中使用request.getParameter("tag")获得我们传递过来的值。为此,我们需要导入java.net.URLEncoder这个包,接下来使用URLEncoder.encode("数据库")来将“数据库”这三个字进行转码得到的结果是“%CA%FD%BE%DD%BF%E2”,如此一来我们的链接就变为了:http://localhost:8080/wwwroot/tagservlet?tag=%CA%FD%BE%DD%BF%E2
然而,当用request.getParameter("tag")获取这个值并将其输出,你会发现是一堆“?”,这里还得在转码才能得到汉字:
String tag = request.getParameter("tag");
tag = new String(tag.getBytes("ISO-8859-1"),"GBK");
这下终于好了,为什么汉字总是这么麻烦,老要转来转去的,老外的字母就没有问题…
以前写的那个[jsp中实现分页显示数据] 方法不通用,得找个分页标签。关于pager-taglib的使用方法网上虽说一大堆,但是同样费我不少脑细胞去看。有的代码不齐全,有的根本就是错误的,有的写的很潦草,看的我是云里雾里的,经过本人耗费大量的脑细胞奋战N个小时终于搞出了点猫腻。
想明白了,写出来运行成功了,我才发现其实用法很简单,没那些人写的那么麻烦。
首先当然还是要导pager-taglib.jar包了,可以去http://jsptags.com/tags/navigation/pager/index.jsp下载,从下载下来的war文件中找到pager-taglib.jar包以及pager-taglib.tld文件。将pager-taglib.tld文件放在WEB-INF目录下,将pager-taglib.jar放在WEB-INF/lib目录下(JBuilder中的导入方法可以参考[Servlet中实现文件上传] )。
新建一个bean文件定义如下两个方法(不一定非要这个样子):
- /**
- * 该方法用于获得数据总数
- * @return int
- */
- public int getArticlesCount() {
- String sql = "SELECT COUNT(*) FROM blog_Article";
- dbc = new DataSource();
- stmt = dbc.getPreparedStatement(sql);
- rs = dbc.getResultSet(stmt);
- int count = 0;
- try {
- if(rs.next()){
- count = rs.getInt(1);
- }
- } catch (SQLException ex) {
- ex.printStackTrace();
- } finally {
- dbc.closeConnection();
- }
- return count;
- }
- /**
- * 该方法用于数据分页
- * @param begin int
- * @param end int
- * @return ArrayList
- */
- public ArrayList getArticlesAll(int begin,int end) {
- String sql = "select top "+end+" * from blog_Article where (log_ID <= (select min(log_ID) from (select top "+begin+" log_ID from blog_Article order by log_PostTime desc) as t)) order by log_PostTime desc";
- ArrayList list = new ArrayList();
- dbc = new DataSource();
- stmt = dbc.getPreparedStatement(sql);
- rs = dbc.getResultSet(stmt);
- try {
- while (rs.next()) {
- ArticleBean article = new ArticleBean();
- article.setId(rs.getInt(1));
- //赋值操作…
- article.setTag(rs.getString(10));
- article.setIsTop(rs.getByte(11));
- list.add(article);
- }
- } catch (SQLException ex) {
- ex.printStackTrace();
- } finally {
- dbc.closeCon
nection(); - }
- return list;
- }
接下来新建一个JSP页面(需要JSTL):
- <%@ page contentType="text/html; charset=GBK" import="java.util.*,com.nkblog.bean.ArticleBean,com.nkblog.dbc.*" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <%@ taglib uri="WEB-INF/pager-taglib.tld" prefix="pg" %>
- <%
- request.setCharacterEncoding("GBK");
- String offset = request.getParameter("pager.offset");//pager.offset为此分页标签内置变量用于传递页数
- int page = 0;
- if(offset == null){
- //若offset为null则是第一次访问,所以显示第一页
- page= 1;
- }else{
- //反之,则按照传递来的页数来分
- page = Integer.parseInt(offset)+1;
- }
- //获取数据总数
- int dataTotal = ArticleManager.getArticlesCount();
- //查询分页数据,10为每页要显示的数据量,可自定义
- ArrayList articles = ArticleManager.getArticlesAll(page,10);
- %>
- <%
- for(int i=0;i<articles.size();i++)
- {
- //输出取出的10条数据…
- }
- %>
- <pg:pager scope="request" maxIndexPages="5" index="center" maxPageItems="10" url="index.jsp" items="<%=dataTotal%>" %>" export="currentPageNumber=pageNumber">
- <pg:first><a href="${pageUrl}">首页</a></pg:first>
- <pg:prev><a href="${pageUrl}">前页</a></pg:prev>
- <pg:page>
- </pg:page>
- <pg:pages>
- <c:choose>
- <c:when test="${pageNumber eq currentPageNumber }">
- <font color="red">${pageNumber }</font>
- </c:when>
- <c:otherwise>
- <a href="${pageUrl }">${pageNumber}</a>
- </c:
otherwise> - </c:choose>
- </pg:pages>
- <pg:next><a href="${pageUrl}">下页</a></pg:next>
- <pg:last><a href="${pageUrl}">尾页</a></pg:last>
- </pg:pager>
接下来具体说明上面的分页标签<pg:pager>
maxIndexPages为分页条个数,形如:< << 1 2 3 4 5 >> >
maxPageItems为每页要显示的数据量
url为处理分页请求的文件,可以是JSP或Servlet。当程序运行起来后,会以index.jsp?pager.offset=5的形式传递页数。
items为数据总数,pager-taglib会自动根据以上参数进行分页。
需要进行修改的也就上面这几个参数,起初看别人写的方法,我以为只要导入这个标签然后给定一个List数据集合,它就完全自动的跟也并显示数据了,汗~~也不知道我这么写会有几个看得懂的,估计懂的人有,但是能看明白我写的就少了…我发现原来代码写起来简单,但是要给别人将明白了真的好难啊。
虽然也学了这么久的J2EE了(基础型),但是我一直都搞不明白:MVC模式是要分三层的,显示层、控制层(业务逻辑层)及数据层,业务逻辑层才能访问数据层,而显示层不能够直接访问数据层。既然如此,那么网站的首页所需要的数据都是来自数据库的,是要动态读取的,这就要在jsp中直接访问数据层,岂不是相互矛盾了吗?
去了几个技术论坛看了看,有人说那只是一个高效的框架模型,不一定非要遵守,可以直接在首页jsp中调用数据层的方法,活人岂能被尿憋死?话虽说有那么点道理,不过我还是不想这么试。
我是这么想的:
方法1.能不能打开网站地址时候访问的第一个文件是一个Servlet,在Servlet中获得首页用于显示所需要的所有数据,然后将它放在request中,接着在使用
request.getRequestDispatcher("index.jsp").forward(request, response);
跳转到真实的首页,如此即可在index.jsp中从request中获得所要的数据了。那么,如何才能打开网址就直接访问Servlet呢?在网站的根目录下WEB-INF中的web.xml中有这么一对标签:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
类似于配置IIS中的默认首页 ,我们把这里的index.jsp改为对应的Servlet即可。
方法2.创建一个过滤器,专门用来过滤首页文件,当请求首页文件时就在过滤器中取数据。过滤器本身其实也是Servlet。
我就晕了,无论用这里面哪一个方法,那这里面的Servlet到底属于哪一层啊?是不是我太钻牛角尖了?
在J2EE的Web开发中(其他的也有),有时我们需要存储一些常量类型的配置信息,而这些信息是在不查询数据库的时候就要能够使用的,我就只想到了两个方法。
一个是存储在XML文件中,使用的时候用AJAX来获取,可是这样需要在客户端写大量的JavaScript代码,如果我们在写Jsp脚本的时候也需要这些信息呢?AJAX也没办法了吧?而且,XML文件是可以直接从URL来访问查看的,虽说不一定是重要的信息,但是能够被人随意看那也不好吧。
第二个方法就是,写在Jsp脚本里面,读取的时候我们可以通过
<%@ include file="" %>这样的[JSP指令] 或者<jsp:include flush="" page="" />[标准动作] 把它包含进当前脚本页即可直接访问它的值。需要修改的时候那就只能用IO流来写进去了。
经过再三斟酌,我决定使用第二个方法。那么,既然是配置信息,那就必须有它的规则(格式),若随便写,那读取起来就不好办了。这里举个实例,比如尼克技术博客使用这个ZBLOG程序,在它的根目录下就有一个类似这样的配置文件c_custom.asp,其代码如下:
- <%
- ‘网站基本设置
- Const ZC_DATABASE_PATH="data/#%206438769b7b43fa552613.mdb"
- Const ZC_BLOG_HOST="http://localhost/"
- ‘——————————————————————–
- Const ZC_BLOG_TITLE="Your Blog"
- Const ZC_BLOG_SUBTITLE="Good Luck To You!"
- Const ZC_BLOG_NAME="你的Blog名称"
- Const ZC_BLOG_SUB_NAME="欢迎使用Z-Blog,有问题或意见请到Zblogger.BBS社区反馈,谢谢您的参与使用。"
- Const ZC_BLOG_CSS="default"
- Const ZC_BLOG_COPYRIGHT="Copyright xxxx-xxxx Your WebSite. Some Rights Reserved."
- Const ZC_BLOG_MASTER="neeke"
- ‘——————————————————————–
- Const ZC_BLOG_THEME="default"
- %>
我们看到它的定义是这样的:
数据类型 关键字名称 = "配置信息"
那么我我们也可以相应的写一个自己的配置文件。
- <%@ page contentType="text/html; charset=GBK" %>
- <%
- String NK_BLOG_TITLE="Your Blog";
- String NK_BLOG_SUBTITLE="Good Luck To You!";
- String NK_BLOG_NAME="你的Blog名称";
- String NK_BLOG_SUB_NAME="欢迎使用NK-Blog!";
- String NK_BLOG_COPYRIGHT="Copyright xxxx-xxxx Your WebSite. Some Rights Reserved.";
- %>
如果在Jsp脚本中需要用他们的时候,我们可以在页头使用<%@ include file="" %>包含这个文件,之后我们就可以直接使用<%=NK_BLOG_TITLE %>来输出“Your Blog”这条信息。修改的时候我们可以使用IO流每次读取其中一行若该行包含有NK_BLOG_TITLE这样的关键字则截取它对应的值,如何截取呢?找每行都有的特征出来,最容易看出来的应该就是双引号啦(""),不过我们不这样截,我们从等号(=)开始截取到分号(;)完,然后替换成新的数据再写入到文件中就OK了!下面就来写具体的实现代码。
读取配置信息:
- public static BlogSetting getBaseSetting(String custom) {
- BlogSetting bset = new BlogSetting();
- //用于存放每行的信息
- &nbs
p; String line = ""; - //用于存储配置信息
- String[] lines = new String[5];
- try {
- //开始读取配置信息
- FileReader fr = new FileReader(custom);
- BufferedReader br = new BufferedReader(fr);
- while ((line = br.readLine()) != null) {
- //keyWords为预定义的特征字符数组
- for (int i = 0; i < keyWords.length; i++) {
- if (line.contains(keyWords[i])) {
- int begin = line.indexOf("=");
- int end = line.indexOf(";");
- //截取配置信息
- String key = line.substring(begin + 2, end - 1);
- //存储
- lines[i] = key;
- }
- }
- }
- //关闭文件流
- br.close();
- fr.close();
- } catch (FileNotFoundException ex) {
- ex.printStackTrace();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- bset.title = lines[0];
- bset.subTitle = lines[1];
- bset.name = lines[2];
- bset.subName = lines[3];
- bset.copyRight = lines[4];
- return bset;
- }
存储配置信息:
- public
span> boolean BaseSettingSave(String custom) { - boolean ok = true;
- //待保存的配置信息
- String[] Words = new String[] {this.title, this.subTitle, this.name,
- this.subName,
- this.copyRight};
- try {
- //开始读取原配置信息
- FileReader fr = new FileReader(custom);
- BufferedReader br = new BufferedReader(fr);
- String line = "";
- String lines = "";
- while ((line = br.readLine()) != null) {
- for (int i = 0; i < keyWords.length; i++) {
- //keyWords为预定义好的特特征字符数组
- if (line.contains(keyWords[i])) {
- int begin = line.indexOf("=");
- int end = line.indexOf(";");
- //截取出要替换掉的配置信息
- String key = line.substring(begin + 2, end - 1);
- //开始替换
- line = line.replaceAll(key, Words[i]);
- }
- }
- //新的配置信息字符串
- lines += line+"\r\n";//*****需要换行符
- }
- //关闭文件流
- br.close();
- fr.close();
- //开始写入新的配置信息
- FileWriter fw = new FileWriter(custom);
- BufferedWriter bw = new BufferedWriter(fw);
- bw.write(lines);
- bw.flush();
- //关闭文件流
- bw.close();
- fw.close();
- } catch (FileNotFoundException ex) {
- ok = false;
- ex.printStackTrace();
- } catch (IOExc
eption ex) { - ok = false;
- ex.printStackTrace();
- }
- return ok;
- }
为什么要写这个呢?因为这个也是我这次J2EE项目中的一部分,JAVA真的忘得差不多了,想到了方法但是如何使用IO流就给忘了,结果翻书找到…温故而知新,写完后读取成功,修改成功,再读取就失败了~ – -!怎么回事呢?因为我修改写入的时候规则丢了,直接用bw.write(lines)写到一行了,第二次读取的时候它找不到规则当然错啦,然后给加上换行符搞定("\r\n")。贴出来以备将来书丢了的时候用,O(∩_∩)O哈哈~
在使用JSP技术开发Web程序的时候,我们所要做的事情,就是在JSP页面中写入Java代码,当服务器运行JSP页面时,执行Java代码,动态获取数据,并生成HTML代码,最终显示在客户端浏览器上。 什么是Servlet Servlet是一个Java程序,是在服务器端运行以处理客户端请求并做出响应的程序。 初识Servlet 下面就让我们来认识一下Servlet吧,Servlet的常见代码如下:
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.io.*;
- import java.util.*;
- public class Servlet1 extends HttpServlet {
- private static final String CONTENT_TYPE = "text/html; charset=GBK";
- //Initialize global variables
- public void init() throws ServletException {
- }
- //Process the HTTP Get request
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws
- ServletException, IOException {
- response.setContentType(CONTENT_TYPE);
- PrintWriter out = response.getWriter();
- out.println("<html>");
- out.println("<head><title>Servlet1</title></head>");
- out.println("<body bgcolor=\"#ffffff\">");
- out.println("<p>The servlet has received a GET. This is the reply.</p>");
- out.println("</body>");
- out.println("</html>");
- out.close();
- application s = new app
- }
- //Clean up resources
- public void destroy() {
- }
- }
注意:创建的Servlet类必须即成HttpServlet类。实现doGet()或者doPost()方法。 Servlet编程模式 懂HTML基础的话就应该知道在HTML中的Form表单的提交方法有两种:GET、POST。这两种方法在提交数据时的差异。Servlet也同样如此。创建Servlet时,必须要继承HttpServlet,HttpServlet作为一个抽象类用来创建用户自己的Servlet,HttpServlet的子类至少重写以下方法中的一个:doGet()和doPost()。HttpServlet类提供doGet()方法处理Form表单中的GET请求,并提供doPost()方法来处理POST请求。