后端部分完全采用springboot的jpa方式进行数据库的操作,在接收请求方面采用的是restful风格。
后端工程目录,如图:
依次为
接下来依次叙述springboot一个实现分类目录列表的每一个类:
@Entity
@Table(name = "category")
@JsonIgnoreProperties({ "handler","hibernateLazyInitializer" })
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
int id;
String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface CategoryDAO extends JpaRepository<Category,Integer>{
}
@Service
public class CategoryService {
@Autowired CategoryDAO categoryDAO;
public Page4Navigator<Book> list(int start, int size, int navigatePages) {
Sort sort = new Sort(Sort.Direction.DESC, "id");
Pageable pageable = new PageRequest(start, size,sort);
Page pageFromJPA =categoryDAO.findAll(pageable); //categoryDAO.findAll方法返回的结果就是一个page对象。当然是jpa中封装好的方法
return new Page4Navigator<>(pageFromJPA,navigatePages);
// return pageFromJPA;
}
public List<Category> list() {
Sort sort = new Sort(Sort.Direction.DESC, "id");
return categoryDAO.findAll(sort);
}
public void add(Category bean){
categoryDAO.save(bean);
}
public void delete(int id){
categoryDAO.delete(id);
}
public Category get(int id){
Category c = categoryDAO.findOne(id);
return c;
}
public void update(Category c){
categoryDAO.save(c);
}
}
@RestController
public class CategoryController {
@Autowired CategoryService categoryService;
@GetMapping("/categories")
public Page4Navigator<Book> list(@RequestParam(value = "start", defaultValue = "0") int start, @RequestParam(value = "size", defaultValue = "5") int size) throws Exception {
start = start<0?0:start;
Page4Navigator<Book> page =categoryService.list(start, size, 5); //5表示导航分页最多有5个,像 [1,2,3,4,5] 这样
return page;
}
@PostMapping("/categories")
public Object add(@RequestBody Category bean){
categoryService.add(bean);
return bean;
}
@DeleteMapping("/categories/{id}")
public String delete(@PathVariable("id") int id,HttpServletRequest request){
categoryService.delete(id);
File imageFile = new File(request.getServletContext().getRealPath("/img/category"));
File file = new File(imageFile,id+".jpg");
file.delete();
return null;
}
@GetMapping("/categories/{id}")
public Category get(@PathVariable("id") int id) throws Exception{
Category bean = categoryService.get(id);
return bean;
}
@PutMapping("/categories")
public Object update(@RequestBody Category bean){
categoryService.update(bean);
return bean;
}
}
点击修改图标,超链地址为(:href为vue超链写法,可以在链接中加vue对象属性):
<a :href="'admin_book_list?cid=' + bean.id ">
@GetMapping(value = "/admin_category_edit")
public String editCategory(){
return "admin/editCategory";
}
<tr class="submitTR">
<td colspan="2" align="center">
<input type="hidden" name="id" v-model.trim="bean.id" >
<a href="#nowhere" class="btn btn-success" @click="update">提 交</a>
</td>
</tr>
$(function () { //$(function(){...})jquery中表示文档一载入完毕就执行
var data4Vue={
uri:'categories',
listURL:'admin_category_list',
bean:{id:0,name:''},
};
var vue = new Vue({
el:'#workingArea',
data:data4Vue,
mounted:function(){
this.get(); //mounted内自动执行
},
methods:{ //methods注意s,不是method
get:function (){ //get方法请求服务器返回该分类对象
var id = getUrlParms("id");
var url = this.uri+"/"+id;
axios.get(url).then(function (response) {
vue.bean = response.data;
})
},
update:function () {
var id = getUrlParms("id");
var url = this.uri;
axios.put(url,vue.bean).then(function (response) {
location.href = vue.listURL;
});
}
}
});
});
新增分类比较简单,比修改简单,直接绑定的按钮执行add函数将请求的地址与bean一起传给服务器,服务器执行成功返回信息时更新列表。但因为整体用的是==restful风格==,因此axios请求插件在修改里用的是==put==方法,增加用的是==post==方法,对应于后端程序中的==PutMapping==和==PostMapping==,这样可以请求一致的url,但后台可以执行不同的方法
跟增加基本无异,但在vue中delete是关键字,在命名delete方法时改成deletebean,并且restful规范删除成功后服务器端要返回null,所以前端进行判断返回的数据是否为null,如果不为空,则打印处数据。
deleteBean:function (id) {
if(!checkDeleteLink())
return;
var url = this.uri+"/"+id;
axios.delete(url).then(function (response) {
if (0!=response.data.length) //rest规范删除数据要求要会返回空字符串(控制器类中delete返回null),所以进行判断
alert(response.data);
else
vue.list(0); //是空字符串则调第一页
})
}
@Entity
public class Book {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
@ManyToOne
@JoinColumn(name = "cid")
private Category category;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public interface BookDAO extends JpaRepository<Book,Integer> {
Page<Book> findByCategory(Category category, Pageable pageable);
//List<Book> findByNameLike(String keyword,Pageable pageable); //这个是后面用到的搜索
}
public Page4Navigator<Book> list(int cid,int start,int size,int navigatePages ){
Category category = categoryService.get(cid); //获取分类对象
Sort sort = new Sort(Sort.Direction.DESC,"id"); //设置排序方式的对象
Pageable pageable = new PageRequest(start,size,sort); //设置分页的对象
Page<Book> pageFromJPA = bookDAO.findByCategory(category,pageable); //DAO中通过分类查询到的结果
return new Page4Navigator<>(pageFromJPA,navigatePages);//返回查询的包含分页信息的书籍项
}
@GetMapping("/categories/{cid}/books")
public Page4Navigator<Book> list(@PathVariable("cid") int cid, @RequestParam(value = "start",defaultValue = "0")int start,
@RequestParam(value = "size",defaultValue = "5")int size){
start = start<0?0:start;
Page4Navigator<Book> page = bookService.list(cid,start,size,5);
return page;
}
搜索书籍功能放在前端的所有书籍页面里面。
<input type="text" class="form-control input-lg col-xs-4" v-model="keyword">
<span @click="listSearch" class="input-group-addon btn btn-primary">
listSearch:function () {
var url = "search?keyword="+vue.keyword;
axios.post(url).then(function (response) {
vue.beans = response.data;
})
},
public interface BookDAO extends JpaRepository<Book,Integer> {
//Page<Book> findByCategory(Category category, Pageable pageable);
List<Book> findByNameLike(String keyword,Pageable pageable);
}
public List<Book> search(String name, int start, int size){
Sort sort = new Sort(Sort.Direction.DESC,"id");
Pageable page = new PageRequest(start,size,sort);
List<Book> books = bookDAO.findByNameLike("%"+name+"%",page);//"%"+name+"%"表模糊查询
return books;
}
在searchController中接收关键字请求信息,返回搜索结果。
@Autowired
BookService bookService;
@PostMapping("/search")
public Object search(@RequestParam(value = "keyword") String keyWord){
return bookService.search(keyWord,0,20);
}
登录功能与前面的分类增加功能类似,前端将表单中的信息use.namer和user.password封装一个json数据user,发送给后端,后端通过注解@Requestbody自动将值赋给usr对象,userDAO将这个对象拿进数据库查询看是否在数据库中。判断后返回result对象,判断里面返回的信息是否是查询成功,成功则跳转到分类页面 ,查询结果为null的话则返回失败信息。
//userDAO添加通过用户名和密码查询的方式
public interface UserDAO extends JpaRepository<User,Integer> {
User getByNameAndPassWord(String name,String password);
}
---
//登录页面的login函数请求服务器
login:function () {
axios.post(vue.uri,this.user).then(function (response) {
vue.result = response.data
if (vue.result.code ==1){
location.href="admin_category_list"
}
else{
alert(vue.result.message)
}
})
}
//在searchController中将传过来的user的name和password进行查询
@RestController
public class LoginController {
@Autowired
UserService userService;
@PostMapping("/login")
public Object login(@RequestBody User userParam, HttpSession httpSession){
User user = userService.get(userParam.getName(),userParam.getPassWord());
if (user==null){
return Result.fail();
} else {
httpSession.setAttribute("user",userParam);
return Result.success();
}
}
}