这是本人第一次写博客,主要记录用java作项目的一些技术点,方便自己日后回忆。
本次java项目是传智播客的“网上书店”项目,用的架构是 jsp + servlet +javabean,这个项目是本人的第一个项目。
以下是自己在做项目的过程中自己觉得需要注意的知识点:
一、request.getParameter 和 request.getAttribute是这两个方法有区别的:
前者是jsp页面中要有的参数,后者是request域中的自己之前存入的键值对此时再拿出来用,比如:
在jsp页面中出现
确认收货
,则因为出现了oid,获取参数值
时是用request.getParameter。${pageContext.request.contextPath }在jsp中表示本项目的意思,order是OrderServlet这个servlet的访问路径(创建servlet时的URL),问号后面全部是参数,参数采用键值对的方式,各个参数之间使用&分隔。
二、隐藏域是用来传递参数给servlet的,比如:
name和value是键值对
三、jsp中的超链接标签既可以直接转发到jsp页面,也可以直接发到servlet。所以有时候需要的参数不够用时,可以先超链接到servlet,用这个servlet把数据存到request域,然后再跳转到下一个页面,下一个页面就可以使用刚刚存入request域中的键值对参数了。
四、一个表单有2个submit时,直接就在submit处的name 和value处写出方法名即可,而在form的action只写到servlet即可,比如:
五、表单的提交方式为post时(即),一定要加隐藏域用来写方法名(写方法名:
)和传参数(传参数:
)。当表单的提交方式为get时,可以直接就写方法名和传参数一步到位(比如:
发货
)。
六、jsp中凡是变量都要加 ${ } ,括号里面写变量和表达式。
七、BeanUtils.populate(javabean , map)方法中map中存在的键值对则可以封装到javabean中,map中没有的键值对则封装不到 javabean中,那么封装不到的剩余属性可以用javabean中的setXXX( )方法来设置。jsp中的name 要和 javabean的属性名字一样才能使用 BeanUtils.populate(javabean , map)进行封装(先用map=request.getParametermap( )
方法得到map,然后再封装)
八、当sql语句为 String countSql = "select count(*) from book where isdel=0;";
时,使用的ResultSetHandler为ScalarHandler,即long totalCountL = (Long) qr.query(countSql, new ScalarHandler());
当sql语句为多表联合查询时(此时结果表一条记录很长很长),有2种解决办法:一是新建一个javabean与该记录对应上,然后用beanhandler处理;
二是使用MapListHandler,即:
String sql2 = “select * from orderitem o ,book b where o.bid=b.bid and o.oid=?;”;
List
for(Order order : oList) {
String sql2 = "select * from orderitem o ,book b where o.bid=b.bid and o.oid=?;";
List
九、关于绝对路径:重定向(response.sendRedirect( )
)和在浏览器中输入网址时二者都要加上项目名;而使用转发时(request.getDispacher( uri ).forward( ))不用加项目名(即uri不用加项目名)。因为重定向可以定位到网络上任何网站和资源,而转发只能在本项目中进行转发。
十、jsp中一定要有page指令(自己老是忘记加上),其实 把request 域 或session域里面的数据动态地、有选择性地添加到jsp 页面时只需要用到
和
这两个jstl就可以了,就这两个jstl语句基本可以实现绝大部分需求了。
十一、步骤:先建库建表 → 再写实体javabean → 再servlet → service → dao/daoImple;其中servlet可以先写个通用基类BaseServlet(该类继承HttpServlet),然后各个功能模块都继承通用基类BaseServlet,要保持一个功能模块对应一个servlet就够了,别对应多个servlet;
其中servlet 、service 直接就是类,而dao层是要先写个接口再写个实现类实现该dao接口。
十二、调用过程:http请求 → 到达后台servlet → servlet 调用 service → service调用 dao → dao操作数据库得到结果集 → dao将结果集返回给service → service返回给servlet →servlet再把数据存到request域或session域中 → jsp 从request域或session域拿出数据展示给用户
十三、跳转到下一个页面有两种方式:转发 和 重定向,其中转发用的更多
十四、如果用BaseServlet作为通用基类(该类继承HttpServlet),后面各个功能模块都继承BaseServlet,那么BaseServlet作为通用基类定义如下:
public class BaseServlet extends HttpServlet{
public void service(HttpServletRequest req , HttpServletResponse resp)
throws ServletException,IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String methodName = req.getParameter("method");
if(methodName == null || methodName.trim().isEmpty()) {
throw new RuntimeException("please input a method !");
}
Class clazz = this.getClass();
Method method = null;
try {
method = clazz.getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException("no such method !");
}
String uri = null;
try {
uri = (String) method.invoke(this, req,resp);
} catch (Exception e) {
e.printStackTrace();
}
try {
if(uri != null && !uri.trim().isEmpty()) {
req.getRequestDispatcher(uri).forward(req, resp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
它的具体过程:http请求→调用HttpServlet的第一个service方法→该HttpServlet的第一个service方法把ServletRequest强转成HttpServletRequest,然后第一个service方法调用第二个service方法并把刚刚强转得到的HttpServletRequest作为函数参数传给第二个service方法→而通用类 BaseServlet重写了第二个service方法,所以第一个service方法调用了通用类 BaseServlet的重写service方法。BaseServlet的重写service方法中使用了反射技术,使用反射技术可以写出很通用的代码。
十五、整个项目分成两个系统,分别是前台系统和后台系统;前台系统是给用户看的,前台系统查询数据库,再将查询结果放到jsp中展示商品给用户购买;后台系统是给卖家用的,卖家在后台系统添加分类和添加图书,结果就是把数据添加到数据库中,前台系统查询数据库得到更新后的数据,所以前台和后台的交互就是通过数据库。
十六、删除数据库中的记录有两种办法:真删除和假删除。真删除就是使用delete的sql语句真正把该记录从数据库中删掉;假删除是逻辑删除,就是在表中增加一个字段isdel,当isdel=0时我们认为记录是存在于数据库的,当isdel=1时我们认为该记录已被删除(实际上该记录仍然存在于数据库中,只是isdel字段的值变了,使用的sql语句是update而不是del)。
十七、从jsp页面往servlet传数据一般是传 ID 值,servlet根据ID值去查询数据库,查询返回给jsp一般是返回一个javabean
或一个List
(也就是把javabean或List存到request域或session域中)。
十八、设计思想:设计方法时方法的形参一般是类的形式最好(往往是javabean,比如:
public void updateBook(Book book)
), 后面写sql语句查询数据库需要参数时用javabean的getXXX()
方法就行(比如book.getBid()
)。体现面向对象的思想。
十九、设计思想:设计javabean
类时属性也可以是一个类,但是后面写sql语句查询数据库需要参数时要用两次javabean的getXXX()
方法,体现面向对象的思想。比如:
public class Order {
private String oid;
private double total;
private String ordertime;
private int state;
private String address;
private User user; //该属性是一个类,这也是一个javabean,后面写sql语句时用两次getXXX()方法即可
private List oilist = new ArrayList();
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public String getOrdertime() {
return ordertime;
}
public void setOrdertime(String ordertime) {
this.ordertime = ordertime;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List getOilist() {
return oilist;
}
public void setOilist(List oilist) {
this.oilist = oilist;
}
}
查询数据库时用两次getXXX()
方法,比如:
public void saveOrder(Connection conn, Order order) {
QueryRunner qr = new QueryRunner();
String sql = "insert into orders values(?,?,?,?,?,?);";
Object[] params = {order.getOid(),order.getTotal(),order.getOrdertime(),
order.getState(),order.getAddress(),*order.getUser().getUid()*};//用了两次getXXX()方法,第一次
try { //getXXX()方法是得到user,第二次getXXX()
qr.update(conn, sql, params); //方法得到user对象中的uid属性
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
二十、jsp页面中凡是涉及到地址的都要在前面加上${pageContext.request.contextPath },也就是包括超链接中的href、图片标签的
中的src属性、form表单的
中的action属性三者都要在前面加上:
${pageContext.request.contextPath }
二十一、src文件夹下至少要建5个包:vo(存放javabean类)、servlet(存放所有servlet类)、service(存放所有service类)、dao(存放所有dao接口和dao接口的实现类daoImple)、util(存放所有工具类);而且src文件夹下还要有c3p0.xml的配置文件(如果用到c3p0的jar包的话)。
二十二、关于分页查询,分页查询要建一个PageBean的javabean,定义如下:
public class PageBean { //这是一个泛型类,以适用于任何类
private int pageCode; //当前页
//private int totalPage; //总页数可以计算出来,所以不需要这个属性
private int totalCount; //总记录数
private int pageSize; //每页存放的记录数
private List beanList;
private String url;
public int getPageCode() {
return pageCode;
}
public void setPageCode(int pageCode) {
this.pageCode = pageCode;
}
public int getTotalPage() {
int totalPage = totalCount / pageSize;
if(totalCount % pageSize == 0) {
return totalPage;
} else {
return totalPage + 1;
}
}
/*public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}*/
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List getBeanList() {
return beanList;
}
public void setBeanList(List beanList) {
this.beanList = beanList;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
在servlet中的方法:
public String findByPage(HttpServletRequest request, HttpServletResponse response) {
int pageCode = getPageCode(request); //得到当前页函数
int pageSize = 3; //每页存放3条记录
BookService bs = new BookService();
PageBean page = bs.findByPage(pageCode,pageSize);
request.setAttribute("page", page);
return "/adminjsps/admin/book/list.jsp";
}
public int getPageCode(HttpServletRequest request) {
String pc = request.getParameter("pc"); //从jsp中获取当前页
if(pc == null || pc.trim().isEmpty()) {
return 1; //返回第一页
}
return Integer.parseInt(pc);
}
用sql语句查询数据库时写法:
public PageBean findByPage(int pageCode, int pageSize) {
PageBean page = new PageBean();
page.setPageCode(pageCode);
page.setPageSize(pageSize);
String countSql = "select count(*) from book where isdel=0;";
QueryRunner qr = new QueryRunner(MyJdbcUtil.getDataSource());
try {
long totalCountL = (Long) qr.query(countSql, new ScalarHandler());
int totalCount = (int) totalCountL;
page.setTotalCount(totalCount);
String limitSql = "select * from book where isdel=0 limit ?,?";
List beanList = qr.query(limitSql, new BeanListHandler(Book.class), (pageCode-1)*pageSize,pageSize);
page.setBeanList(beanList); //存的是当前页的信息
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return page;
}
在jsp页面中:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
图书分类
二十三、jsp文件、图片文件、css和.js文件、MANIFEST.MF和 *.sql 文件都要放在WebRoot根目录下,要创建文件夹来分别装这些文件,以方便分类。在WebRoot目录下有个WEB-INF文件夹,这个文件夹下有个lib文件夹和web.xml文件;lib文件夹用来存放这个项目所需要的第三方jar包(我们所导入的第三方jar包就放在这里,直接把这些包复制粘贴到lib下就行),web.xml文件主要描述servlet和欢迎文件的配置信息。
二十四、javabean类中只要有getXxxx()
方法,就算在这个bean中没有明显地定义写出xxxx属性,那么这个属性xxxx也是存在的,在jsp页面中可以直接使用${ javabean.xxxx }
。这是因为它符合规范:get后面第一个字母大写,且有返回值,那么xxxx就是一个属性,可以直接使用这个属性。
二十五、在浏览器中只输入到项目名为止然后看到的页面是什么取决于在web.xml文件中的index.jsp这个的配置。本项目在浏览器中只输入到项目名为止看到的页面是index.jsp文件。
index.jsp
二十六、前台系统的jsp等文件和后台系统的jsp等文件都是放在WebRoot根目录下,前台和后台共用servlet、service、dao/daoImple这些类,前台和后台只是往这些类增加不同的方法而已。
二十七、jsp中的 标签和
标签是合一起的,即
标签的name和
标签的value是一对键值对。
二十八、form表单一定是直接提交到servlet,而超链接即可以到servlet,也可以到jsp页面。
二十九、自己做的网页如果想和网络上的其他任何网站发生连接必须要用重定向发给浏览器,不能用转发,因为转发只能在本项目内转发,而重定向可以定位到任何页面。
三十、get请求在jsp中的url写法:直接就是${pageContext.request.contextPath }/servlet?method=methodName&参数名=参数值&参数名=参数值...
;
而post请求必须加隐藏域,url写法:${pageContext.request.contextPath }/servlet
//写到servlet即可
再加上 //这个是写方法的
传参数还要加:
如果要传多个参数,则继续加: