好的,作为一个新人的第一篇文章。。。以及在工作期间完成的第一个任务(但不是第一个接到的任务),困扰我20多天(好吧,请减掉10天的出差和几个双休日)的任务。。。
很多地方是有值得反思的内容的。
(在显眼的地方提醒,在写这一大堆东西的时候。。。我的累计程序时间不到200小时(应该))
于是。。。
1.技术部分之前
我知道,这个JSP让我的师傅看起来比较难看的接受了。。。因为这个任务只有一个JSP,一个连简单的CSS都写在里面的JSP,一个JSP完成搜索、分页、部分CSS。。。
我知道我现在的技术很差,而且我也知道常规来说,应该是分开的。。。
而且,由于代码本身有很多要求。。。这里提供的代码是有大量的删减和修改(为了避免透露所在单位的信息)...以及我懒得开mysql再建一个表....
以及,严格意义上来说这是我第一次用JSTL写东西。。。
还有,这是我第一次写博文(以前百度空间时代的东西除外)(如果csdn有博文的规范请务必告诉我。。。给个链接....谢谢大佬们)
.........
....好吧,我直接说好了-别完全相信我的文档!在做着任务的时候被百度坑(无效搜索,以及使用错误的信息带来的无效写代码,改代码,以及因为上述原因导致的奔溃)的时间比写代码本身的时间还多!
如果你去问人一个问题,对面甩给你一句:“百度啊!”...请回他:“如果百度能解决所有问题还发展语义搜索干嘛?IBM的Watson此情何堪?是不是要砍了所有的真人专家以及竞争平台给百度让路?“.......基于3连击要带上一个EX的原则,可以补充一句:”百度还有莆度众生啊!“
好的,之前一句是开玩笑,因为作为一名菜鸟,绝大多数的问题是很难百度出来的...只少百度很难给你现成的答案,而新人又缺乏辨别、拆解组装、描述问题等能力...真的能问人会更快。
2.技术部分-代码
重要提示-代码的原型-http://www.runoob.com/jsp/jsp-database-access.html
(还有很多想不起来的。。。想起起来我会补充)
<%@ page language="java" pageEncoding="gb2312"%>
<%@ page import="java.io.*,java.util.*,java.sql.*"%>
<%@ page import="javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>
嗯,我知道似乎不少完全没用到,但是出于习惯还是写了
2个关于JSTL的是关键。
之后我懒了,把部分讲解丢到了代码里面
<body>
<%
response.setCharacterEncoding("gb2312");
%>
<c:if test="${empty param.currentPage}">
<c:set var="currentPage" value="0"/>
</c:if>
<c:if test="${not empty param.currentPage}">
<c:set var="currentPage" value="${param.currentPage}"/>
</c:if>
<!--万恶之源之一....currentPage是从0开始,而之后一个关于分页的内容是从1开始...大家明白要发生了什么吧?-->
<c:set var="c_id" value="${param.c_id}"/>
<c:set var="c_name" value="${param.c_name}"/>
<!--这里的目的是接受来自url(分页)的信息-尤其是页码-->
<c:set var="PerPageNum" value="10"/>
<!--要改变一页多少条记录,请修正这里PerPageNum的值-->
<form action="MyJsptest21.jsp" method="post">
<h3>请输入需要查询的公司id或公司名称</h3>
请输入公司id:<input type="text" name="c_id" value="${c_id}" />
请输入公司名称:<input type="text" name="c_name" value="${c_name}" />
<input type="submit" value="提交" >
</form>
<!--这里是表单,2个text有默认值,在通过url进行换页或者提交表单进行搜索的时候,上一次查询的条件会留在这里-->
<!--可能存在潜在风险,如果我在分页操作的时候改了text里面的内容会如何?-->
<c:set var="S_C_id" value="%${c_id}%"/>
<c:set var="S_C_name" value="%${c_name}%"/>
<c:if test="${empty c_id}">
<c:set var="S_C_id" value="空名称"/>
<c:set var="Do_and" value="0"/>
</c:if>
<c:if test="${empty c_name}">
<c:set var="S_C_name" value="空名称"/>
<c:set var="Do_and" value="0"/>
</c:if>
<!--这里的内容是尝试读取来自分页和表单的text的内容,并且尝试判断是不是2个text都填写了进入and搜索-->
<!--以及,任务要求是2个条件同时输入的时候是AND搜索,用户只输入一个的是OR搜索-->
<!--S_C_XX是搜索时用的条件,Do_and是判断是否进入了and判断的条件-->
<!--在c_xx为空值的时候,输入一个“不可能有实际结果”的值-例如“空名称”-作为条件参加搜索-->
<!--以及...为什么不直接来个<c:set var="S_C_XXX" value="%${param.c_name}"/>?-->
<!--1是有待优化。2是为了空名称套入。3是为了区分情况。4是...我还没有优化。-->
<sql:setDataSource var="snapshot" driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://XXX.XXX.XXX.XXX:XXXX/XXXX"
user="XXXX" password="XXXXXXX"/>
<!--一大堆XXXXXX?我说过我要隐藏具体信息-->
<sql:query dataSource="${snapshot}" var="result">
<c:choose>
<c:when test="${Do_and == 0}">
select ab.c_id as id,cd.c_name as name,ab.abc as abc,ab.cde as cde
from XXXXX ab inner XXXXX cd
on ab.c_id=cd.c_id
where cd.c_id LIKE ?
<sql:param value="${S_C_id}" />
or cd.c_name LIKE ?
<sql:param value="${S_C_name}" />
order by cd.cid;
</c:when>
<c:when test="${empty Do_and }">
select ab.c_id as id,cd.c_name as name,ab.abc as abc,ab.cde as cde
from XXXXX ab inner XXXXX cd
on ab.c_id=cd.c_id
where cd.c_id LIKE ?
<sql:param value="${S_C_id}" />
and cd.c_name LIKE ?
<sql:param value="${S_C_name}" />
order by cd.cid;
</c:when>
</c:choose>
</sql:query>
<!--我知道搜索这样写的比较难看,但是基本的语句不会乱掉-->
<!--嗯。。。请不要直接使用数据库...理论上and和or可以并在一起,但编码的时候一直报错...-->
<!-- 以及,sql语句本身是凭空改的。。。为了不暴露具体内容 -->
<!-- 有2个表,ab和cd,2个表都有c-id,ab表还有abc和cde,原任务中的2个要求查询的具体内容,cd表还有c-name -->
<c:set var="resultNum">
<jsp:getProperty name="result" property="rowCount" />
</c:set>
<!--resultNum是这一个查询有多少结果,用来为之后的分页做准备-->
<%
//这里还是用java,因为有取整问题。。。我不打熟悉jstl的取整
int perPageNum = Integer.parseInt((String) pageContext
.getAttribute("PerPageNum"));
int resultNum = Integer.parseInt((String) pageContext
.getAttribute("resultNum"));
int pageNum = (int) (resultNum / perPageNum + 1);
pageContext.setAttribute("pageNum",pageNum);
//这里可能有问题,因为我并不熟悉java和jstl的变量的传递。。。可能有多于的代码
%>
<c:if test="${resultNum != 0}">
<!--这个判断的目标是为了美观。。要不然在没有结果或者刚进入页面的时候都会看见光秃秃的结果信息-->
<!-- 这里应该用非空。。。搜索没结果和还没做搜索“应该”是2种情况 -->
<!-- 相信我,“应该”这个词通常存在本身就很...有价值。。。如果有心理咨询师经验的人应该会认同... -->
<table border="1" width="100%">
<caption>查询结果</caption>
<tr>
<th>公司id</th>
<th>公司名称</th>
<th>公司abc</th>
<th>公司cde</th>
</tr>
<c:forEach var="row" items="${result.rows}"
begin="${currentPage*PerPageNum}"
end="${PerPageNum+currentPage*PerPageNum-1}">
<tr class="isdata">
<td><c:out value="${row.c_id}"/></td>
<td><c:out value="${row.c_name}"/></td>
<td><c:out value="${row.abc}"/></td>
<td><c:out value="${row.cde}"/></td>
</tr>
</c:forEach>
</table>
<!--结果显示完成。之后就是头痛的分页了-->
共<c:out value="${resultNum }"/>条记录
<c:choose>
<c:when test="${currentPage == 0}">
到头了
</c:when>
<c:otherwise>
<c:url var="lastURL" value="test2/MyJsptest21.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${currentPage-1}"/>
</c:url>
<a href="/<c:out value="${lastURL}"/>">上一页</a>
</c:otherwise>
</c:choose>
<!-- 这里就是上一页和到头的实现。。。下一页和到尾了的。。。到时候就不提醒了 -->
<c:choose>
<c:when test="${pageNum <= 9}" >
<c:forEach var="i" begin="1" end="${pageNum}">
<c:url var="littleURL" value="test2/MyJsptest20.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${i-1}"/>
</c:url>
<c:choose>
<c:when test="${currentPage + 1 != i}" >
<a href="/<c:out value="${littleURL}"/>">第<c:out value="${i}"/>页</a>
</c:when>
<c:otherwise>
第<c:out value="${i}"/>页
</c:otherwise>
</c:choose>
</c:forEach>
<!--这里是结果小于10页记录的分页-->
<!--等于呢?-->
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${currentPage < 6}" >
<c:forEach var="i" begin="1" end="10">
<c:url var="big1URL" value="test2/MyJsptest20.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${i-1}"/>
</c:url>
<c:choose>
<c:when test="${currentPage + 1 != i}" >
<a href="/<c:out value="${big1URL}"/>">第<c:out value="${i}"/>页</a>
</c:when>
<c:otherwise>
第<c:out value="${i}"/>页
</c:otherwise>
</c:choose>
</c:forEach>
<!--这里是结果大于10页记录的分页,其中的头6页。。。因为都是从第一页开始,第十页结束-->
<!--这里易错/有待优化....原因是“到问题”和“边界值问题”-->
<!--这里的6准确的说是5+1...5是“当前页前面5页”-->
</c:when>
<c:when test="${currentPage >= pageNum - 4}" >
<c:forEach var="i" begin="${pageNum-9}" end="${pageNum}">
<c:url var="big3URL" value="test2/MyJsptest20.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${i-1}"/>
</c:url>
<c:choose>
<c:when test="${currentPage + 1 != i}" >
<a href="/<c:out value="${big3URL}"/>">第<c:out value="${i}"/>页</a>
</c:when>
<c:otherwise>
第<c:out value="${i}"/>页
</c:otherwise>
</c:choose>
</c:forEach>
<!--这里是结果大于10页记录的分页,处理的是最后4页,页码到了最后四页,结尾和开头都不会变化-->
<!--这里易错/有待优化....原因是“到问题”和“边界值问题”-->
<!--这里的4的的确确就是“当前页的后面4页”-->
</c:when>
<c:otherwise>
<c:forEach var="i" begin="${currentPage - 4}" end="${currentPage + 5}">
<c:url var="big2URL" value="test2/MyJsptest20.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${i-1}"/>
</c:url>
<c:choose>
<c:when test="${currentPage + 1 != i}" >
<a href="/<c:out value="${big2URL}"/>">第<c:out value="${i}"/>页</a>
</c:when>
<c:otherwise>
第<c:out value="${i}"/>页
</c:otherwise>
</c:choose>
</c:forEach>
<!--这里是结果大于10页记录的分页,其中不是前2种的中间情况-->
<!--这里易错/有待优化....原因是“到问题”和“边界值问题”-->
<!--这里的-4和+5的的确确会令人弄晕,但是请记住,和I比currentPage自带-1... -->
<!--所以,-4意味着“当前页前面5页”,而+5意味着“当前页的后面4页”...请自带-1 -->
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
<c:choose>
<c:when test="${currentPage+1 == pageNum}">
到尾了
</c:when>
<c:otherwise>
<c:url var="nextURL" value="test2/MyJsptest20.jsp">
<c:param name="c_id" value="${c_id}"/>
<c:param name="c_name" value="${c_name}"/>
<c:param name="currentPage" value="${currentPage+1}"/>
</c:url>
<a href="/<c:out value="${nextURL}"/>">下一页</a>
</c:otherwise>
</c:choose>
</c:if>
</body>
</html>
。。。。。。
如果你还在,现在就开始描述一下分页部分的逻辑
分页至少有2中,一种是以当前页为中心显示有限页数;一种是规定一个值(通常是10),进10页换一次
这里用的是当前页数为中心。并且是一口气显示10页,并且中间只显示前5后4(嗯,这里是按照百度的...我本来想要看看P站的,但是我还没有不敬业到在单位看P站)
本质上就4中情况。。。用伪码表示如下
if(结果不超过10页){
直接把结果从第一页刷到最后一页
}
else{
if(当前页在头6页){
直接把结果从第一页刷到第十页
}
else if(当前页在尾4页){
直接把结果从尾-9页刷到尾页
}
else{
直接把结果从当前页-5刷到当前页+4
//这里容易出现问题。。。我这里的currentPage是从0开始,而我实际上用来用来递归和表示当前页数(用户看见的)的I是从1开始的
//到问题是我的弱点,所以自己用的使用要明辨...至少留一个”这里可能出错“的标记
}
}
3.技术部分-非代码部分
第一-学语言的第一目标不是为了精通,而是搞懂能做什么、不能做什么、与习惯的语言有什么不同...特别是与习惯语言的不同.......是的,jstl的when要套chose,而if没有else.......
遇到的主要BUG就是when用了没套chose。。。以及url部分,最开始尝试用传统的a herf。。。但是死活报错,最后看见了菜鸟教程关于c:param的描述才写成这样并且完成
第二-会学如何描述问题(也就是如何搜索)....我知道我在第一部分吐槽过。。。真的,我是由于太腼腆没有敢去问师傅...更主要的是我不知道如何描述问题。
关于如何改善?老老实实买书(或者看对口的技术文章)....但是买什么?我承认我的自学能力差...老老实实去问师傅或者看看单位的公用书柜。
(当然,有人会吐槽为什么不会去自己找书。。。能找到正确的书的人,还是菜鸟吗?)
(而且,敏锐的朋友应该发现了,我这里用的词是”正确的书“...正确这个词本书和”应该“一样,值得玩味...在我得情境下,对书籍的阅读和推荐者是有极大关系的...也就是说-一本好书如果是我自己找的,我可能不回去看;如果是来自一个我尊敬的人...情况会乐观很多)
第三-微笑地看待推荐过来的视频-在做这个任务受困的时候尝试向同学求助,其中一个人非常非常友善的发来一大堆视频......
我表示感谢,而且那些视频一个没看(在完成这个任务的过程中)....因为我不知道那个能解决问题!
而且!而且!视频这种媒介的特征是重视过程,而我需要的仅仅是解决”如何做“的问题!这种时候问人,书面资料等方式读取信息所带来的”干扰“(无用消息)更少!
如果我傻乎乎的去看视频找。。。我今天应该还没完成任务。。。
以及通常的博文还有什么请告诉我...不胜感激。(运行测试结果?嗯。。。等有空)