新增操作
当登陆成功之后会跳转到frameset框架中,点击左侧的新增书籍链接跳转到新增页面,本次的新增页面中包含了书籍类型,书籍出版社,作者的所在地,这几个内容都要从表中进行读取,所以会单独建立相关的操作,在新增的时候,还需要添加操作的用户信息,所以会在控制层中读取登录时设置的session属性“uid”,然后将其设置到书籍信息中。
书籍类型,书籍出版社设置
1、建立BookType.java类
package cn.mldn.szq.model;
import java.io.Serializable;
public class BookType implements Serializable{
private Integer typeId;
private String typeName;
}
2、建立IBookTypeDAO.java接口
package cn.mldn.szq.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import cn.mldn.szq.model.BookType;
public interface IBookTypeDAO {
@Select("SELECT type_id AS typeId,type_name AS typeName FROM p_booktype")
public List<BookType> findAll();
}
3、建立IBookTypeService.java接口以及实现类BookTypeServiceImpl.java类
package cn.mldn.szq.service;
import java.util.List;
import cn.mldn.szq.model.BookType;
public interface IBookTypeService {
public List<BookType> list();
}
package cn.mldn.szq.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.mldn.szq.mapper.IBookTypeDAO;
import cn.mldn.szq.model.BookType;
import cn.mldn.szq.service.IBookTypeService;
@Service
public class BookTypeServiceImpl implements IBookTypeService{
@Resource
private IBookTypeDAO typeDAO;
@Override
public List<BookType> list() {
return this.typeDAO.findAll();
}
}
4、建立BookTypeController.java类
package cn.mldn.szq.controller;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.mldn.szq.model.BookType;
import cn.mldn.szq.service.IBookTypeService;
@Controller
@RequestMapping("booktype")
public class BookTypeController {
@Resource
private IBookTypeService typeService;
@RequestMapping("listAll")
@ResponseBody
public List<BookType> list(){
return this.typeService.list();
}
}
由于出版社的操作与类型的操作完全一样,所以此处只是列出实体类BookPress.java以及
package cn.mldn.szq.model;
import java.io.Serializable;
public class BookPress implements Serializable{
private Integer pressId;
private String pressName;
}
package cn.mldn.szq.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import cn.mldn.szq.model.BookPress;
public interface IBookPressDAO {
@Select("SELECT press_id AS pressId,press_name AS pressName FROM p_bookpress")
public List<BookPress> findAll();
}
地址设置
地址操作中,包括了坐着的省地址和市地址,正如数据库表“p_area”所设计的思路,所有的省的“area_parid ”设置为“0”,而每个省所属的市区的“area_parid ”设置为所在省的“area_id”的值,按照如下的方式设置,在地区的时候,如果分别查询省和市,需要查询两次,而如果每次在查询的时候,判断一下,就可以省很多事。具体设置如下:
1、创建实体类Location.java
package cn.mldn.szq.model;
import java.io.Serializable;
@SuppressWarnings("serial")
public class Location implements Serializable {
private int locationID;
private String locationName;
private int locationPID;
}
其中将“locationID”和“locationPID”设置为“int”类型,是考虑到,每次查询的时候,如果页面会给后台传递一个location实体对象,如果没有传递,则表示按照默认值进行查询,也就是省信息的查询
2、创建ILocationDAO.java接口
package cn.mldn.szq.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Select;
import cn.mldn.szq.model.Location;
public interface ILocationDAO {
@Select("SELECT area_id AS locationID,area_title AS locationName FROM p_area"
+" where area_parid = #{locationPID}")
public List<Location> findAll(Location location);
}
其中判断条件“area_parid = #{locationPID}”中,“locationPID”是从页面中传递过来的“locationID”,具体如下设置
3、创建ILocationService.java接口以及LocationServiceImpl.java实现类
package cn.mldn.szq.service;
import java.util.List;
import cn.mldn.szq.model.Location;
public interface ILocationService {
public List<Location> list(Location vo);
}
package cn.mldn.szq.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.mldn.szq.mapper.ILocationDAO;
import cn.mldn.szq.model.Location;
import cn.mldn.szq.service.ILocationService;
@Service
public class LocationServiceImpl implements ILocationService {
@Resource
private ILocationDAO locationDAO;
@Override
public List<Location> list(Location vo) {
return this.locationDAO.findAll(vo);
}
}
4、创建LocationController.java
package cn.mldn.szq.controller;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.mldn.szq.model.Location;
import cn.mldn.szq.service.ILocationService;
@Controller
@RequestMapping("location")
public class LocationController {
@Resource
private ILocationService locationServcice;
@RequestMapping("list")
@ResponseBody
public List<Location> listlocation(Location location){
location.setLocationPID(location.getLocationID());
return this.locationServcice.list(location);
}
}
页面会给控制层传递一个省的“locationID”值,以方便查询相关的市区,所以此处将页面传递过来的“locationID”的值,赋值给“locationPID”,是为了方便思路上的对应关系。如果不设置此处的话,其实也是可以进行正常执行的,只不过在DAO层调用的属性就应该是“locationID”。
新增设置
有了之前的准备,在接下来就可以直接针对于Book来进行操作,只要在页面中将所需要的信息进行整合即可传递过来。
1、建立实体类
package cn.mldn.szq.model;
import java.io.Serializable;
import cn.mldn.szq.util.PageUtil;
public class Book implements Serializable{
private Integer bookId;
private String bookName;
private String bookAuthor;
private String bookCover;
private Double bookPrice;
private Integer bookTypeId;
private Integer bookPressId;
private Integer bookStatus;
private String bookAddTime;
private String bookLabel;
private String bookDesc;
private Integer authorProId;
private Integer authorCityId;
private Integer userId;
}
上面的信息都只是对应于数据库表“p_book”的基础字段
2、建立IBookDAO.java
package cn.mldn.szq.mapper;
import java.util.List;
import cn.mldn.szq.model.Book;
public interface IBookDAO {
public void doCreate(Book vo);
}
由于book的操作比较多,所以此处会使用映射文件进行相关方法的实现比较方便
3、建立book-mapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.mldn.szq.mapper.IBookDAO"><!--此处设置相应的持久层接口-->
<insert id="doCreate" parameterType="Book">
INSERT INTO p_book(book_id,book_name,book_author,book_cover,
book_price,book_type_id,book_press_id,book_status,book_add_time,
book_label,book_desc,author_proid,author_cityid,user_id)
VALUES(mo_sq.nextval,#{bookName},#{bookAuthor},#{bookCover},
#{bookPrice},#{bookTypeId},#{bookPressId},#{bookStatus},to_date(#{bookAddTime},'yyyy-MM-dd'),
#{bookLabel},#{bookDesc},#{authorProId},#{authorCityId},#{userId})
</insert>
</mapper>
此处的“<insert>”标签中的“id”属性,需要与“IBookDAO.java”接口中相应的方法设置相同,同时设置好相应的参数“parameterType”设置要传递的参数类型,因为在spring-mybatis.xml文件中配置好了具体的model路径,所以此处的实体类参数不需要设置具体的包路径,只需要写类名即可。
4、建立IBookService.java以及实现类BookServiceImpl.java
package cn.mldn.szq.service;
import java.util.Map;
import cn.mldn.szq.model.Book;
public interface IBookService {
public void add(Book vo);
}
package cn.mldn.szq.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.mldn.szq.mapper.IBookDAO;
import cn.mldn.szq.model.Book;
import cn.mldn.szq.service.IBookService;
@Service
public class BookServiceImpl implements IBookService {
@Resource
private IBookDAO bookDAO;
@Override
public void add(Book vo) {
this.bookDAO.doCreate(vo);
}
}
5、建立BookController.java
在添加数据的时候,需要进行文件的上传操作,所以需要设置相应的上传文件的操作,同时由于前台页面的上传操作使用的是layui的上传组件,所以需要单独设置一个文件上传的控制层路径。
要访问“addBook.ftl”文件,由于拦截器的存在,所以需要单独设置访问路径,否则不能访问到页面。
新增操作的时候需要记录用户的信息,而保存用户信息的内容放在了session属性范围“uid”,所以不会再前台页面传递过来,需要在控制层取出该属性值,并未前台接收过来的Book实体类中的“userId”设置对应的内容。
package cn.mldn.szq.controller;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import cn.mldn.szq.model.Book;
import cn.mldn.szq.service.IBookService;
import cn.mldn.szq.util.UpDownPicture;
@Controller
@RequestMapping("book")
public class BookController {
@Resource
private IBookService bookService;
@RequestMapping("add")
@ResponseBody
public String add(HttpServletRequest request,Book vo){
Integer uid = (Integer) request.getSession().getAttribute("uid");
if(vo != null){
vo.setUserId(uid);
this.bookService.add(vo);
}
return "{}";
}
@RequestMapping("toAddftl")
public String toAddftl(){
return "book/addBook";
}
@RequestMapping("uploadBookCover")
@ResponseBody
Map<String,Object> uploadBookCover(HttpServletRequest request,MultipartFile bookCover) {
return UpDownPicture.uploadPhoto(request, bookCover);
}
}
至此,后台的基本内容编写完毕,接下来,需要在前台的“addBook.ftl”文件中将所需要的内容进行整合显示。
完成addBook.ftl文件
1、设置基本的添加字段,并且引入所需要的laiui的js脚本和样式,并且将jQuery的开发包也导入进来。
<#assign base=request.contextPath />
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="${base}/plugins/layui/css/layui.css">
<link rel="stylesheet" href="${base}/plugins/layui/css/modules/layer/default/layer.css">
</head>
<body>
<form id="add_book_form">
<input type="hidden" id="add_book_cover" name="bookCover">
<table border="1">
<tr>
<td>书籍名称</td>
<td>
<input name="bookName">
</td>
</tr>
<tr>
<td>书籍作者</td>
<td>
<input name="bookAuthor">
</td>
</tr>
<tr>
<td>书籍封面</td>
<td>
<button type="button" class="layui-btn" id="uploadPic">
<i class="layui-icon"></i>上传头像
</button>
</td>
</tr>
<tr>
<td> 预览图:</td>
<td>
<blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
<div class="layui-upload-list" id="demo1">
<p id="demoText"></p>
</div>
</blockquote>
</td>
</tr>
<tr>
<td>书籍价格</td>
<td>
<input name="bookPrice">
</td>
</tr>
<tr>
<td>书籍类型</td>
<td>
<select id="bookTypeId" name="bookTypeId">
<option value="-1">--请选择--</option>
</select>
</td>
</tr>
<tr>
<td>书籍出版社</td>
<td>
<select id="bookPressId" name="bookPressId">
<option value="-1">--请选择--</option>
</select>
</td>
</tr>
<tr>
<td>文章状态</td>
<td>
<input type="radio" name="bookStatus" value="1"/>上架
<input type="radio" name="bookStatus" value="2"/>下架
</td>
</tr>
<tr>
<td>发布日期</td>
<td>
<input id="add_book_date" name="bookAddTime">
</td>
</tr>
<tr>
<td>文章标签</td>
<td>
<input type="checkbox" name="bookLabel" value="1"/>校园
<input type="checkbox" name="bookLabel" value="2"/>青春
<input type="checkbox" name="bookLabel" value="3"/>政治
<input type="checkbox" name="bookLabel" value="4"/>经济
</td>
</tr>
<tr>
<td>书籍描述</td>
<td>
<input name="bookDesc" id="bookDesc">
</td>
</tr>
<tr>
<td>作者所在省</td>
<td>
<select id="authorProId" name="authorProId">
<option value="-1">--请选择--</option>
</select>
</td>
</tr>
<tr>
<td>作者所在市</td>
<td>
<select id="authorCityId" name="authorCityId">
<option value="-1">--请选择--</option>
</select>
</td>
</tr>
<tr>
<td colspan="2">
<input type="button" value="提交" id="add_book">
</td>
</tr>
</table>
</form>
<script type="text/javascript" src="${base}/plugins/jquery.min.js"></script>
<script src="${base}/plugins/layui/layui.all.js"></script>
</body>
</html>
2、为日期、简介、图片上传设置相应的layui组件
<script>
//初始化layui相关组件
layui.use(['form', 'upload', 'layedit', 'laydate'], function(){
var form = layui.form;
var upload = layui.upload;
var edit = layui.layedit;
var laydate = layui.laydate;
//初始化编辑器
bookEditor = edit.build("bookDesc"); //其中写富文本简介的id,不加“#”
data_sync = function() {
edit.sync(bookEditor);
}
//初始化日期控件
laydate.render({
elem:"#add_book_date" //写需要添加日期插件的input的“id”,这里需要加“#”
});
var ssdd1;
//普通图片上传--封面
var uploadInst = upload.render({
//绑定上传组件到具体的标签上
elem: '#uploadPic'
//文件上传的后台方法
,url: '${base}/book/uploadBookCover'
//文件上传到后台的对象的属性名,如:此处Book中图片的属性为bookCover,控制层接收的参数要与此对应
,field:"bookCover"
//是否开启多文件上传
,multiple:true
//文件上传之前调用,弹出模态窗口
,before: function(obj){
ssdd1 = layer.open({
type: 1
,title: false //不显示标题栏
,closeBtn: false
,shade: 0.4
,moveType: 1 //拖拽模式,0或者1
,content: '<i class="layui-icon layui-anim layui-anim-rotate layui-anim-loop"></i>'
});
//预读本地文件示例,不支持ie8
obj.preview(function(index, file, result){
$('#demo1').html('<img height="80px" src="'+ result +'" alt="'+ file.name +'" class="layui-upload-img">')
});
}
,done: function(data){
//当一次上传结束之后回调函数
$("#add_book_cover").val(data.filepath);
layer.close(ssdd1);
}
,error: function(){
//演示失败状态,并实现重传
var demoText = $('#demoText');
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-mini demo-reload">重试</a>');
demoText.find('.demo-reload').on('click', function(){
uploadInst.upload();
});
}
});
});
</script>
此处的引入中,需要注意的是富文本编辑器的在引入的时候不需要为相应的<input>表单的“id”属性加“#”;
但是在日期插件的<input>的“id”属性需要加“#”;
并且还需要设置文件上传的访问路径,以及绑定触发的控件“id”,然后设置好与实体类对应的参数名称“field”
绑定要预览的位置,因为此处打开了多文件上传,所以如果需要多图片预览的时候,需要修改“$('#demo1').html()”为“$('#demo1').append()”即可。
3、设置相应的类型,和出版社
$(function(){
//类型
$.ajax({
url:"${base}/booktype/listAll",
type:"post",
dataType:"json",
data:"{}",
success:function(data){
for(var x = 0; x < data.length ; x ++){
add_select_Row("bookTypeId",data[x].typeId,data[x].typeName);
}
}
});
//出版社
$.ajax({
url:"${base}/bookpress/listAll",
type:"post",
dataType:"json",
data:"{}",
success:function(data){
for(var x = 0; x < data.length ; x ++){
add_select_Row("bookPressId",data[x].pressId,data[x].pressName);
}
}
});
//省
$.ajax({
url:"${base}/location/list",
type:"post",
dataType:"json",
data:"{}",
success:function(data){
for(var x = 0; x < data.length ; x ++){
//console.log(data[x].locationID +","+ data[x].locationName);
add_select_Row("authorProId",data[x].locationID,data[x].locationName);
}
}
});
});
$("#authorProId").on("change",function(){
//市
var parentId = $(this).val();
$.ajax({
url:"${base}/location/list",
type:"post",
dataType:"json",
data:{locationID:parentId},
success:function(data){
$("#authorCityId option:gt(0)").remove();
for(var x = 0; x < data.length ; x ++){
//console.log(data[x].locationID +","+ data[x].locationName);
add_select_Row("authorCityId",data[x].locationID,data[x].locationName);
}
}
});
});
function add_select_Row(eleId,contentId,contentTitle){
$("#"+eleId).append(
"<option value='"+ contentId +"'>"+ contentTitle +"</option>"
);
}
类型,和出版社,以及省的设置都需要在页面加载的时候进行设置好,而市区的设置却需要在省进行变化时在动态的进行访问添加,也就是二级联动,而此处需要注意的是,因为我使用的是append()方法,所以每次在添加市区的时候,需要先删除之前的内容“$("#authorCityId option:gt(0)").remove();”
4、最后进行表单的提交处理
//提交表单
$("#add_book").click(function() {
//进行数据同步
data_sync();
$.ajax({
url:"${base}/book/add",
data:$("#add_book_form").serialize(),
type:"post",
dataType:"json",
success:function(data) {
alert("新增成功")
location.href = "${base}/book/list";
}
});
});
此处需要将富文本编辑其中设置的内容同步到该内容中。
至此,所以的添加任务完成。
其中,在控制层进行的上传图片所调用的方法封装为UpDownPicture.java:
package cn.mldn.szq.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
public class UpDownPicture {
/**
* <pre>uploadPhoto(这里用一句话描述这个方法的作用)
* @param request : HttpServletRequest的对象
* @param Photo :所要上传的图片文件
* @return 将保存好的文件名称以Map形式返回</pre>
*/
public static Map<String,Object> uploadPhoto(HttpServletRequest request,MultipartFile Photo){
Map<String,Object> map = new HashMap<String,Object>();
if(Photo.getSize() > 0){
String realpath = request.getServletContext().getRealPath("/") + "/upload/";
File file = new File(realpath);
if(!file.exists()){
file.mkdirs();
}
String originalFilename = Photo.getOriginalFilename();
String newFileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
try {
Photo.transferTo(new File(realpath + newFileName));
map.put("filepath", "/upload/" + newFileName);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return map;
}
/**
* <pre>downLoadFile(这里用一句话描述这个方法的作用)
* 用于图片下载操作
* @param response :HttpServletResponse对象
* @param request:HttpServletRequest对象
* @param photoTitle:要下载的图片名称</pre>
*/
public static void downLoadFile(HttpServletResponse response, HttpServletRequest request, String photoTitle) {
String realPath = request.getServletContext().getRealPath("/") + photoTitle;
File file = new File(realPath);
if (file.exists()) {
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
response.setHeader("Content-Type", "application/octet-stream");
FileInputStream inputStream = null;
ServletOutputStream outputStream = null;
try {
inputStream = new FileInputStream(file);
outputStream = response.getOutputStream();
byte[] b = new byte[1024];
int read = inputStream.read(b);
while (-1 != read) {
outputStream.write(b);
outputStream.flush();
//读取下一次
read = inputStream.read(b);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (null != outputStream) {
try {
outputStream.close();
outputStream = null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (null != inputStream) {
try {
inputStream.close();
inputStream = null; //方便GC更快回收
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}