博主名取自《小羊肖恩》中的小羊肖恩,名字为:肖恩,音译为Sean,自己取的姓:阿奇,为符合我们的阅读习惯,连起来组成为ArchieSean。博主目前大三在读,志在将博客打造成为个人线上笔记的技术栈,方便自己也方便他人。如博客中有任何错误,请各位指出,谢谢大家。
- 写在前边:
该小练习基于Maven工程创建,如果不熟悉maven,可使用普通工程创建,只需将resoueces下的配置文件放在普通项目的src根目录下,并且将所需的jar包导入到WEB-INF下的lib文件中即可。为方便起见, 我就直接使用Maven构建项目。练习中的书写方式,各层之前存在较强的耦合性,如有强迫症可以使用工厂模式进行解耦,使用读取配置文件+反射的方式来创建各层对象。
技术选型
使用的技术有:
bootstrap+jq+ajax+servlet+beanutils+objectMapper+javabean+druid+jdbcTemplete+MySQL
当然使用jsp+el+jstl也可以实现数据显示。
前期准备
当然,数据库表的设计,我使用的是我之前用过的一个现成的表。
在搭建项目之前,使用bootstrap书写如下简单的页面。
搭建环境
创建maven工程,导入坐标,创建三层的包,导入配置文件和工具类,导入前端页面。
-
工程目录结构;
-
配置文件
这里可能由于数据库的不同,driverClassName和url的值有有点区别。较新的mysql版本需要分别设置为com.mysql.cj.jdbc.Driver和在url后边加上时区。 -
导入的坐标(练习所需要的jar包)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
- 三层的准备
- 表现层:
- 使用baseservlet来抽取(利用反射)
- 在productServlet中声明ProductService成员变量
- 业务逻辑层:
- 书写接口
- 实现其接口,重写其方法,声明productDao成员变量
- 持久层:
- 书写接口
- 实现其方法,声明jdbcTemplete成员变量
以上各层,在下文中都会有所体现。
- 表现层:
功能实现
实现增加功能
使用异步的方式实现。
- product的javabean:
package com.test.domain;
import java.io.Serializable;
import java.math.BigDecimal;
public class Product implements Serializable {
private Integer pid; //表的主键
private String name; //商品名称
private String note; //商品描述
private BigDecimal priice; //商品价格
private Integer amount; //商品数量
@Override
public String toString() {
return "Product{" +
"pid=" + pid +
", name='" + name + '\'' +
", note='" + note + '\'' +
", priice=" + priice +
", amount=" + amount +
'}';
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public BigDecimal getPriice() {
return priice;
}
public void setPriice(BigDecimal priice) {
this.priice = priice;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
}
- 结果判断javabean
package com.test.domain;
import java.io.Serializable;
public class ResultInfo implements Serializable {
private boolean flag; //操作是否成功的标记
private Object data; //返回的数据
private String message; //错误信息
@Override
public String toString() {
return "ResultInfo{" +
"flag=" + flag +
", data=" + data +
", message='" + message + '\'' +
'}';
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- 表现层
@WebServlet("/product/*")
public class ProductServlet extends BaseServlet {
private ProductService service = new ProductServiceImpl();
public void saveProduct(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
request.setCharacterEncoding("utf-8");
Map<String, String[]> map = request.getParameterMap();
Product p = new Product();
BeanUtils.populate(p, map);
int i = service.saveProduct(p);
ResultInfo info = new ResultInfo();
if (i > 0) {
info.setFlag(true);
} else {
info.setFlag(false);
info.setMessage("保存失败");
}
response.setContentType("application/json;charset=utf-8");
new ObjectMapper().writeValue(response.getWriter(), info);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
- 业务逻辑层
public class ProductServiceImpl implements ProductService {
private ProductDao dao=new ProductDaoImpl();
@Override
public int saveProduct(Product p) {
return dao.saveProduct(p);
}
}
- 持久层
package com.test.dao.impl;
import com.test.dao.ProductDao;
import com.test.domain.Product;
import com.test.utils.JDBCUtils;
import org.springframework.jdbc.core.JdbcTemplate;
public class ProductDaoImpl implements ProductDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public int saveProduct(Product p) {
String sql = "insert into product values(null,?,?,?,?)";
int i = template.update(sql, p.getName(), p.getNote(), p.getPriice(), p.getAmount());
return i;
}
}
- 测试
分页查询功能实现
- 分析:
- 分页工具类
package com.test.domain;
import java.util.List;
public class PageBean<T> {
private int totalCount;//总记录数
private int totalPage;//总页数
private int currentPage;//当前页码
private int pageSize;//每页显示的条数
private List<T> list; //每页显示的数据集合
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
- 表现层
public void selectByPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//获取当前页
String currentPage = request.getParameter("currentPage");
String pageSize = request.getParameter("pageSize");
if (currentPage == null || "".equals(currentPage)) {
currentPage = "1";
}
if (pageSize == null || "".equals(pageSize)) {
pageSize = "5";
}
// 获取条件查询的值
Map<String, String[]> map = request.getParameterMap();
PageBean<Product> pb = service.selectByPage(currentPage, pageSize, map);
response.setContentType("application/json;charset=utf-8");
System.out.println(pb);
new ObjectMapper().writeValue(response.getWriter(), pb);
}
- 业务逻辑层
public PageBean<Product> selectByPage(String current_Page, String pageSize, Map<String, String[]> map) {
int currentPage = Integer.parseInt(current_Page);
if (currentPage <= 0) {
currentPage = 1;
}
int page_size = Integer.parseInt(pageSize);
PageBean<Product> pb = new PageBean<Product>();
pb.setCurrentPage(currentPage);
pb.setPageSize(Integer.parseInt(pageSize));
//总记录数
int totalCount = dao.findTotalCount(map);
pb.setTotalCount(totalCount);
//查询list
int start = (currentPage - 1) * page_size ;
List<Product> list = dao.findByPage(start, page_size , map);
pb.setList(list);
int totalPage = totalCount % page_size == 0 ? totalCount / page_size : totalCount / page_size + 1;
pb.setTotalPage(totalPage);
return pb;
}
- 持久层
/**
* @return int
* @Description //查询总记录数
* @Param [map]
**/
@Override
public int findTotalCount(Map<String, String[]> map) {
String sql = "select count(*) from product where 1=1";
StringBuilder sb = new StringBuilder(sql);
Set<String> keySet = map.keySet();
List<Object> list = new ArrayList<Object>();
for (String s : keySet) {
if ("name".equals(s)) {
String value = map.get(s)[0];
if (value != null && !"".equals(value)) {
sb.append(" and " + s + " like ?");
list.add("%" + value + "%");
}
}
}
System.out.println(sb.toString());
return template.queryForObject(sb.toString(), Integer.class, list.toArray());
}
/**
* @return java.util.List<com.test.domain.Product>
* @Description //查询list
* @Param [start, i, map]
**/
@Override
public List<Product> findByPage(int start, int i, Map<String, String[]> map) {
String sql = "select * from product where 1=1 ";
StringBuilder sb = new StringBuilder(sql);
Set<String> keySet = map.keySet();
ArrayList<Object> list = new ArrayList<Object>();
for (String s : keySet) {
if ("name".equals(s)) {
String value = map.get(s)[0];
if (value != null && !"".equals(value)) {
sb.append(" and " + s + " like ? ");
list.add("%" + value + "%");
}
}
}
sb.append(" limit ?,?");
list.add(start);
list.add(i);
System.out.println(sb.toString());
System.out.println(list);
return template.query(sb.toString(), new BeanPropertyRowMapper<Product>(Product.class), list.toArray());
}
此时后台所有的分页操作都已实现,此时可以在浏览器来测试一下:
当看到响应的json数据时,说明后端代码已没有任何问题。
-
前端
前端页面中使用ajax发送异步请求的方式来实现,并将响应的json数据显示在页面之上。 -
分页组件
分页使用的是bootstrap提供的分页组件,该部分功能的实现,需要明确的是不同的页码之间只是currentPage的区别,而上一页下一页也同理,要在点击上一页的时候判断当前的currentPage是否是第一页,如果是第一页,那么将上一页置为不可点击,同理下一页也是同理。
在我们平时见到的网页里边,也有分页组件中有页面直接跳转的效果,这个实现也是一样的,获取用户input:text中所输入值,将该值作为currentPage即可实现。还有每次页码的数量都是固定的,这个也可以通过js来实现。
修改功能的实现
在上边分页的基础上,在查询出来的操作功能中实现修改功能。修改的基本思路是查询数据库,数据回显,数据更新即可。在这里分页查询已做过一次查询,这里修改我直接使用js获取之前查询到的内容来做数据回显。
实现的效果: 点击上图的修改之后,“跳转"到修改页面(这里,加” “是因为,整个练习在一个index.html的页面,并不存在页面间的跳转)之后显示如下界面,进行数据回显
此时就可以编辑,进行数据修改了。。
删除功能的实现
要实现的效果点击删除,删除掉商品信息。
具体实现思路: 将页面上隐藏的商品的主键传到后台去,进行删除操作即可。
- 实现效果
总结
这是一个简单的CRUD的基本练习,目的是为了再次熟悉分页的基本思路。为之后使用PageHelper能做一个简单的对比。
如有任何问题,欢迎指正。