
在不考虑分页功能的情况下,本项目是非常简单的,核心功能也只是增删改查而已。
这些很简单,就是html而已,这边不会的,直接搜标签。
' method=post>
以post方式,将表单提交至\CustomerServlet中。
小疑问:既然这里说以post方式提交,为什么CustomerServlet里没有doPost()呢?我们原来学的里面都要重写doPost()和doGet()方法啊。
![]()
为解决这个问题,需要了解BaseServlet这个类。这个类重写了service方法,导致doGet和doPost都没用了。但是我觉得不应该重写service方法,而是应该重写doGet和doPost方法。
具体解释见帖:
https://blog.csdn.net/u010452388/article/details/80723550
再仔细看BaseServlet类,发现
String methodName = request.getParameter(‘"method");
再看add.jsp中有一句话,
发现了么,通过隐藏控件将add.jsp绑定了一个提交事件(method=add) ,然后BaseServlet类接收到,之后通过反射调用方法名为methodName的方法(本例中为add)
method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
总结:add/edit/delete/query.jsp都是这样,发送一个(method = xxx),然后BaseServlet接收到,并在service方法中通过反射调用xxx()。在本例中,add.jsp发送method=add,然后BaseServlet接收到methodName = add,然后在CustomerServlet(BaseServlet的子类)中调用实现了的add()。
疑问:为什么要采用这种方式?我们可以在doGet中写若干个if—else语句,从而判断method的值,然后来调用相应的函数。你看,HTTPServlet类的service就是你这么做的,根据不同的HTTP协议头(GET/POST/…)来派发给不同的函数做,用反射不是很麻烦吗?
回答:因为设计模式中,要对修改封闭,对添加开放——意思是原有的代码就不要改了,鼓励增加代码而不是修改代码。你想,如果现在你是CURD四个功能,如果之后功能需求越来越多,那就要添加更多的if……else代码,并且还要修改之前的,维护起来很困难采用这种方法,只要jsp中的method增加一个xxx,然后在servlet中添加一个对应的xxx方法即可实现view和controller的绑定,岂不妙哉?
至于为什么HttpServlett的service采用了if—else,那是因为,HTTP协议头的内容比较固定啊,就post/get/…但是你的项目不一样,甲方很可能给你临时添加不少需求的。
题外话:
我不知道你有没有学过MFC或者QT之类的桌面软件的开发工作,如果你拖动一个按钮(相当于jsp中的input),然后你需要对这个按钮绑定一个事件(相当于servlet中的方法),你可以右键绑定一个事件,即将控件和方法绑定起来。其实本质上,baseservlet就是做了这么一件简单的事儿。
相当于QT或者MFC里面的MessageBox,用来弹出一个页面作为提示。
在CustomerServlet中,将字符串msg的信息写入request域中,然后通过forward转发到msg.jsp中,在通过EL表达式展示出来。
但是你在CustomerServlet中只能看到add()方法返回了一个字符串/msg.jsp,但是跳转这一步在哪里进行呢?
还是BaseServlet。
try {
String result = (String)method.invoke(this, request, response);
if (result != null && !result.trim().isEmpty()) {
int index = result.indexOf(":");
if (index == -1) {
((HttpServletRequest)request).getRequestDispatcher(result).forward((ServletRequest)request, response);
} else {
String start = result.substring(0, index);
String path = result.substring(index + 1);
if (start.equals("f")) {
((HttpServletRequest)request).getRequestDispatcher(path).forward((ServletRequest)request, response);
} else if (start.equals("r")) {
response.sendRedirect(((HttpServletRequest)request).getContextPath() + path);
}
}
}
methodName方法(比如add方法)的返回值,通常采用返回字符串的方式,通过前缀来决定功能。比如说返回值为f:msg.jsp表示forward过去,r:msg.jsp表示redirect重定向过去,d:a.img表示下载。也可以设置无前缀时默认为forward转发。
所以,虽然add方法只返回一个/msg.jsp的字符串,但是在service方法中,其实已经利用了这个字符串forward到了相应的地址上了。
这里,baseservlet已经讲解完毕了。
除了分页的逻辑代码之外,有一处可以讲一下。
${cstm.name}
${cstm.gender}
${cstm.phone}
${cstm.email}
${cstm.description}
编辑
删除
主要是熟悉一下核心标签库中foreach的用法, 还有为什么&id=${cstm.id}呢?其实就是把id发过去,之后好在数据库中根据id删除记录。
从jsp,到baseservlet再到customerservlet,讲到这里,基本上除了数据库操作,基本的流程都结束了。
总结一下:
将原始数据打包成对象,以add为例。
Customer customer = CommonUtils.toBean(request.getParameterMap(), Customer.class);
//通过反射将map中国的元素赋值一个一个的幅值到customer,然后组成一个完整的对象
customer.setId(CommonUtils.uuid());
customerService.add(customer);
再看toBean这个函数:
public static T toBean(Map map, Class clazz) {
try {
T bean = clazz.newInstance();
ConvertUtils.register(new DateConverter(), Date.class);
BeanUtils.populate(bean, map);
return bean;
} catch (Exception var3) {
throw new RuntimeException(var3);
}
}
本质上是把map中的键值对一个一个的填充到类里,其实这很好理解。
类A 属性a,b,c,d
Map (a,1) (b,2) (c,3) (d,4)
我问你,你能根据Map得到一个A的对象么?当然可以了,相当于A的一个对象叫aa,然后属性a=1,b=2,c=3,d=4。那么BeanUtils.populate(bean, map)其实就是这个意思。
UUID:
类似于MAC网卡,IP地址或者二维码,也可是说是身份证,简单而言就是一组在三千年内不会重复的一串数字字母的组合。原来主键大家用自增的数字,12345等等,但是这样有问题,比如两个库要合并,就会导致主键重复,而采用UUID就不存在这样的问题,这是绝对唯一的,3000年内。
3中已经成功创建好了Customer对象,比如对象c好了,可以通过getXxx()方法获得c的全部属性值,然后放入数据库,就那么简单。
public void add(Customer c)
{
try {
String sql = "insert into t_customer values(?,?,?,?,?,?)";
Object[] params = {c.getId(), c.getName(), c.getGender(),
c.getPhone(), c.getEmail(), c.getDescription()};
//将params的参数带入并取代?
qr.update(sql, params);
}catch (Exception e)
{
throw new RuntimeException(e);
}
}
这个类就是用起来舒服一点的数据库操作类,其实本质都一样,就是sql语句挖个空(占位符/通配符),然后用string类型字符串去拼接他,实现动态sql语句的功能。下面给出相关的一些小知识点,想知道特别具体的,可以百度或谷歌。
我在考虑写不写这个项目里关于分页的内容,感觉逻辑比较多,但是并不难。。。