本项目最后一篇博文,讲药品后台。
JavaBean
药品部分涉及到两个JavaBean,一个Agents药品,一个PageBean<E>按页查询。
先看Agents对象。
package com.rclv.domain;
import java.util.Date;
public class Agents {
private String aid; // 药品Id
private String aname; // 品名
private String aimg; // 图片
private String aboard; // 品牌
private String aNo; // 货号
private String aCAS; // CAS号
private String aspec; // 规格
private Integer count; // 数量
private String aunit; // 单位
private String astore; // 存放地
private String asup; // 供应商
private Date adate; // 入库日期
private User user; // 聚合一个User对象,代表入库人
// 省略set、get方法
}
Agents中的成员变量都是药品的一些属性,最后一个变量是聚合了一个User对象,作为当前药品的入库人。我们需要记录是哪个用户入库了某个药品,所以通过聚合实现一个单向关联的关系,即用户和药品是一对多的关系。
再看PageBean<E>。
package com.rclv.domain;
public class PageBean<E> {
private List<E> list; // 封装Agents
private Integer currPage; // 当前页码
private Integer pageSize; // 每页显示数量
private Integer totalPage; // 总页数
private Integer totalCount; // 数据总数量
// 省略其他set、get方法
public Integer getTotalPage() {
return (int)Math.ceil(totalCount*1.0/pageSize);
}
public PageBean() { }
public PageBean(List<E> list, Integer currPage, Integer pageSize, Integer totalCount) {
super();
this.list = list;
this.currPage = currPage;
this.pageSize = pageSize;
this.totalCount = totalCount;
}
}
PageBean的作用是实现分页查询,其中的成员变量是些和页码相关的属性,并聚合了List<E>泛型类存储主要的查询数据。PageBean的总页数totalPage由totalCount和pageSize计算出:return (int)Math.ceil(totalCount*1.0/pageSize)。
(1)按页查询药品
package com.rclv.web.servlet;
public class AgentsServlet extends BaseServlet {
// 分页展示药品
public String findAgentsByPage(HttpServletRequest request, HttpServletResponse response) throws Exception {
//1.返回当前页数,并设置每页显示总个数
int currPage=Integer.parseInt(request.getParameter("currPage"));
int pageSize=12;
//2.调用service,返回pagebean
AgentsService as = (AgentsService) BeanFactory.getBean("AgentsService");
PageBean<Agents> agentsBean=as.findAgentsByPage(currPage,pageSize);
//3.将结果放入request中 请求转发
request.setAttribute("ab", agentsBean);
return "/jsp/agents_list.jsp";
}
}
控制层。
第一步。获取前台当前页码currPage,并设置每页显示数量pageSize。
第二步。调用service层方法,findAgentsByPage(currPage,pageSize),查询药品,并返回一个PageBean<Agents>对象agentsBean。
第三步。将agentsBean属性设置到request域中,并请求转发到agents_list.jsp页面。
package com.rclv.service.impl;
public class AgentsServiceImpl implements AgentsService {
@Override
public PageBean<Agents> findAgentsByPage(int currPage, int pageSize) throws Exception {
AgentsDao ad = (AgentsDao) BeanFactory.getBean("AgentsDao");
// 1.调用dao层,查询返回当前页数据
List<Agents> list=ad.findAgentsByPage(currPage,pageSize);
// 2.调用dao层,查询返回所有药品总数量
int totalCount = ad.getTotalCount();
// 3.传入所有实参,返回新建PageBean。
return new PageBean<>(list, currPage, pageSize, totalCount);
}
}
业务层。
第一步。调用dao层findAgentsByPage(currPage,pageSize)方法,查询返回参数为Agents的List集合。
第二步。调用dao层getTotalCount()方法,查询返回药品总数量totalCount。
第三步。传入所有实参,返回新建PageBean。
package com.rclv.dao.impl;
public class AgentsDaoImpl implements AgentsDao {
@Override
public List<Agents> findAgentsByPage(int currPage, int pageSize) throws Exception {
// 1.创建QueryRunner对象qr并连接数据库,创建sql查询语句
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select * from agents order by adate desc limit ?,?";
// 2.执行数据库查询,方法第二个参数表示要返回一个参数为Agents的List集合
List<Agents> list = qr.query(sql, new BeanListHandler<>(Agents.class), (currPage-1)*pageSize, pageSize);
// 3.循环遍历,对list中的每一个Agents对象再次进行查询操作。查询aid为当前agents.aid的agents内连接user后的数据,
// 并返回为一个List<Map<String, Object>>集合。
for (Agents agents : list) {
sql = "select * from agents a, user u where a.uid = u.uid and a.aid = ?";
List<Map<String, Object>> mlist = qr.query(sql, new MapListHandler(), agents.getAid());
for (Map<String, Object> map : mlist) {
// 4.新建User对象,并将map集合内所有的键值映射到user中对应的属性。最后以set方法将user添加到agents中。
User user = new User();
BeanUtils.populate(user, map);
agents.setUser(user);
}
}
return list;
}
// 查询agents的总数
@Override
public int getTotalCount() throws Exception {
// 1.创建数据库连接,查询语句为聚合函数查询agents总数量。
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "select count(*) from agents";
// 2.ScalarHandler用来查询封装单个结果值,返回值为Object类型,所以在这里先强转为Long型,再转为int类型。
return ((Long)qr.query(sql, new ScalarHandler())).intValue();
}
}
持久层。
findAgentsByPage(currPage,pageSize)方法。
第一步。创建QueryRunner对象qr并连接数据库,创建sql查询语句,根据agents表中的adate降序排序,limit限定查询数量。
第二步。调用qr.query(sql, new BeanListHandler<>(Agents.class), (currPage-1)*pageSize, pageSize)方法进行数据库查询,方法第二个参数表示要返回一个参数为Agents的List集合,第三、四个参数替代sql语句的占位符,表示查询从当前页第一个数据开始的pageSize个数据。
第三步。foreach循环语句。对list中的每一个Agents对象再次进行查询操作。查询语句sql表示查询aid为当前agents.aid的agents内连接user后的数据,并返回为一个List<Map<String, Object>>集合。其实mlist中只有一个Map集合,但是我们依然用foreach语句操作其中的Map集合。
第四步。新建一个User对象。用BeanUtils.populate(user, map)方法,将上一步中查询到的内联数据map集合内所有的键值映射到user中对应的属性。最后用set方法将user添加到agents中。
第四步的目的就是给agents设置user变量值,只是过程麻烦了点,需要一次内敛查询、一次映射封装和一次set方法。
getTotalCount()方法。
第一步。创建数据库连接,查询语句为聚合函数查询agents总数量。
第二步。执行数据库查询操作。qr.query(sql, new ScalarHandler())用来查询封装单个结果值,返回值为Object类型,所以在这里先强转为Long型,再转为int类型。
至此,分页查询后台功能完成,我们再回到前台。
<!-- jstl的forEach语句展示EL获得从后台传来的数据 -->
<tbody>
<c:forEach items="${ab.list }" var="a">
<tr>
<td>${a.aname }</td>
<!-- 鼠标悬停放大图片,以及点击添加图片 -->
<td class="picsTd">
<div id="picsMagnify">
<!-- 此处省略 -->
<input name="${a.aname }" value="${a.aid }" style="display: none;" />
</div>
</td>
<td>${a.aboard}</td>
<td>${a.aNo}</td>
<td>${a.aCAS}</td>
<td>${a.aspec}</td>
<td>${a.count}</td>
<td>${a.aunit}</td>
<td>${a.astore}</td>
<td>${a.asup}</td>
<td>${a.user.uname}</td>
<td>${a.adate}</td>
<!-- 点击修改药品损耗情况 -->
<td>
<button type="button" class="btn btn-default" name="${a.aid }" value="${a.count}" onclick="showDiv(this)" >损耗</button>
</td>
</tr>
</c:forEach>
<tbody>
<!--分页查询 -->
<div style="width:380px;margin:0 auto;margin-top:20px;">
<ul class="pagination" style="text-align:center; margin-top:10px;">
<!-- 判断当前页是否是首页 -->
<c:if test="${ab.currPage == 1 }">
<li class="disabled">
<a href="javascript:void(0)" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
</c:if>
<!-- 此处省略 -->
</ul>
</div>
<!-- 分页结束-->
后台查询返回的PageBean对象添加到了request域中的ab属性,前台agents_list.jsp中,用EL表达式${ab.list }取出PageBean中的List集合,用forEach表达式展示list中的agents各属性。另外,${ab.currPage }用做当前页的判断。
(2)药品入库
// 商品入库
public String add(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1.判断用户是否登陆,未登陆先跳转
User user = (User) request.getSession().getAttribute("user");
if(user == null) {
request.setAttribute("msg", "请先登录");
return "/jsp/msg.jsp";
}
// 2.将前端传来的数据放入map集合,然后封装到一个Agents类里
Map<String, String[]> map = request.getParameterMap();
Agents agents = new Agents();
BeanUtils.populate(agents, map);
// ConvertUtils.register(new MyConventer(), Date.class);
// 3.给agents实例设置日期和用户属性
agents.setAdate(new Date());
agents.setUser(user);
// 4.调用service完成药品入库功能,并重定向到按页查询的Servlet请求
AgentsService as = (AgentsService) BeanFactory.getBean("AgentsService");
as.add(agents);
response.sendRedirect(request.getContextPath() + "/agents?method=findAgentsByPage&currPage=1");
return null;
}
控制层。
第一步。判断用户是否登陆,若未登录,则设置msg属性值,并跳转到msg.jsp消息页面。
第二步。用Map集合获取前台传入的所有入库药品信息,新建Agents对象,将map中的键值映射到agents中。
第三步。给agents设置当前时间和当前用户。
第四步。调用AgentsService.add(Agents agents)方法进入service层。最后,重定向到按页查询的Servlet请求。
业务层。
这里直接调用AgentsDao.add(Agents agents)方法进入dao层。
// 完成数据库增加操作
@Override
public void add(Agents agents) throws Exception {
// 1.连接数据库,创建查询语句为插入语句,用占位符表示要添加的字段值。
QueryRunner qr = new QueryRunner(DataSourceUtils.getDataSource());
String sql = "insert into agents values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
// 2.qr.update()方法执行数据库插入操作,其中的参数通过获取Agents的变量值来传参,对应sql语句占位符。
qr.update(sql, agents.getAid(), agents.getAname(), agents.getAimg(),
agents.getAboard(), agents.getaNo(), agents.getaCAS(),
agents.getAspec(), agents.getCount(), agents.getAunit(),
agents.getAstore(), agents.getAsup(), agents.getAdate(),
agents.getUser().getUid());
}
持久层。
第一步。连接数据库,创建查询语句为插入语句,用占位符表示要添加的字段值。
第二步。qr.update()方法执行数据库插入操作,其中的参数通过获取Agents的变量值来传参,对应sql语句占位符。
至此,完成药品入库的后台功能。
(3)药品损耗
// 更新药品损耗
public String update(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1.前台传入药品aid,数量,损耗量
int oAid = Integer.parseInt(request.getParameter("oAid"));
int oCount = Integer.parseInt(request.getParameter("oCount"));
int dif = Integer.parseInt(request.getParameter("dif"));
// 2.计算药品损耗后的数量,调用service完成数量跟新
int nCount = oCount - dif;
AgentsService agents = (AgentsService) BeanFactory.getBean("AgentsService");
agents.update(oAid, nCount);
// 3.重定向到按页查询的Servlet请求
response.sendRedirect(request.getContextPath() + "/agents?method=findAgentsByPage&currPage=1");
return null;
}
控制层。
第一步。获取药品Id、原数量和损耗量。
第二步。计算损耗后的数量,并调用AgentsService.update(int oAid, int nCount)方法进入service层。
第三步。重定向到按页查询的Servlet请求。
业务层。
直接调用AgentsDao.update(int oAid, int nCount)方法进入dao层。
控制层。
根据药品id完成简单的条件更新操作。
(4)添加或更新图片
package com.rclv.web.servlet;
public class AddImageServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 1.创建map 放入前台传递的数据
HashMap<String, Object> map = new HashMap<>();
// 2.创建磁盘文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
// 3.创建核心上传对象
ServletFileUpload upload = new ServletFileUpload(factory);
// 4.解析request,返回List集合,参数为FileItem类
List<FileItem> list = upload.parseRequest(request);
// 4.foreach遍历集合
for (FileItem fi : list) {
// 5.判断是否是普通的上传组件
if(fi.isFormField()){
// 普通上传组件
// 将key-value放入map中
map.put(fi.getFieldName(),fi.getString("utf-8"));
}else{
// 6.文件上传组件
// 6.1获取文件名称
String name = fi.getName();
// 6.2获取文件的真实名称
String realName = UploadUtils.getRealName(name);
// 6.3获取文件的随机名称
String uuidName = UploadUtils.getUUIDName(realName);
// 7.获取文件的存放路径
String path = this.getServletContext().getRealPath("/aimg/1");
// 8.获取文件输入流
InputStream is = fi.getInputStream();
// 9.创建输出流
FileOutputStream os = new FileOutputStream(new File(path, uuidName));
// 10.将输入流数据复制到输出流,并关闭输入输出流
IOUtils.copy(is, os);
os.close();
is.close();
// 11.删除临时文件
fi.delete();
// 12.在map中设置图片的路径
map.put(fi.getFieldName(), "aimg/1/"+uuidName);
}
}
// 13.新建Agents对象,并将map的键值映射到agents中。
Agents agents = new Agents();
BeanUtils.populate(agents, map);
// 14.调用AgentsService.addImgs(Agents agents)方法进入dao层。
AgentsService as = (AgentsService) BeanFactory.getBean("AgentsService");
as.addImgs(agents);
// 15.重定向到按页查询的Servlet请求
response.sendRedirect(request.getContextPath() + "/agents?method=findAgentsByPage&currPage=1");
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("msg", "商品添加失败~");
request.getRequestDispatcher("/jsp/msg.jsp").forward(request, response);
return;
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
控制层。
AddImageServlet没有继承BaseServlet,而是直接继承HttpServlet,并重写doGet方法来完成图片上传功能。
第一步。创建Map集合,用来传入前台传递的数据。
第二步。创建磁盘文件项DiskFileItemFactory类对象。
第三步。创建ServletFileUpload核心上传对象。
第四步。解析request,返回List集合,参数为FileItem类。
第五步。foreach遍历list集合中的FileItem对象fi。判断fi是否是普通的上传组件,若是,则直接将fi的key-value放入map中。
第六步。fi是文件上传组件。则获取fi文件名称,再获取文件真是名称,再转为UUID随机名称。
第七步。this.getServletContext().getRealPath("/aimg/1")方法获取文件存放路径。此路径为apache项目部署路径。
第八步。获取文件输入流InputStream类对象。
第九步。创建文件输出流FileOutputStream类对象。
第十步。通过IOUtils.copy(is, os)方法将输入流数据复制到输出流,并关闭输入输出流。此数据为临时数据,服务器重启即消失。
第十一步。删除临时文件。
第十二步。在map中设置图片的路径。
第十三步。新建Agents对象,并将map的键值映射到agents中。
第十四步。调用AgentsService.addImgs(Agents agents)方法进入service层。
第十五步。重定向到按页查询的Servlet请求。
业务层。
直接调用AgentsDao.addImags(Agents agents)方法进入dao层。
持久层。
根据药品id条件更新药品的aimg属性。
至此,后台药品所有功能讲完。