1.dao层
public interface CategoryDAO extends JpaRepository<Category,Integer>{
}
只用创建一个接口,继承JpaRepository类就可以了
然后传入两个泛型参数,第一个为实体类名,第二个为id的类型,因为查看JpaRepository的源码发现,在执行一些getOne()根据id查询一个对象,方法时会传入第二个泛型参数
这里用到了一个findAll()方法,其中的一个实现可以传入Sort对象,这里用到的就是这个实现
/*
* (non-Javadoc)
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
List<T> findAll(Sort sort);
Sort对象是对排序操作的一个封装类,后面说到Service层时还会提到
2.pojo层
实体类只有两个属性 id 和 name
@Entity
@Table(name = "category")
@JsonIgnoreProperties({
"handler","hibernateLazyInitializer"
})
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
int id;
String name;
}
(1).其中需要在实体类上标注@Entity注解,还有@table注解绑定数据库中的表
(2).id属性用@Id注解,表明这是id,@GeneratedValue注解,标注自动生成策略,还有@Column注解,绑定数据库中的属性id
经过上面两步就可以实体类映射了
3.Service层
@Service
public class CategoryService {
@Autowired
CategoryDAO categoryDAO;
public List<Category> list() {
Sort sort = new Sort(Sort.Direction.ASC,"id");
return categoryDAO.findAll();
}
}
首先需要注入Dao类
然后创建一个list方法,返回一个Category类的List
这里讲解一下Sort类
/**
* Creates a new {@link Sort} instance.
*
* @param direction defaults to {@linke Sort#DEFAULT_DIRECTION} (for {@literal null} cases, too)
* @param properties must not be {@literal null}, empty or contain {@literal null} or empty strings.
*/
public Sort(Direction direction, String... properties) {
this(direction, properties == null ? new ArrayList<String>() : Arrays.asList(properties));
}
这是这里调用的Sort类的初始化方法这里其实调用了Arrays.aslist方法,然后就是这个方法
/**
* Creates a new {@link Sort} instance.
*
* @param direction defaults to {@linke Sort#DEFAULT_DIRECTION} (for {@literal null} cases, too)
* @param properties must not be {@literal null} or contain {@literal null} or empty strings.
*/
public Sort(Direction direction, List<String> properties) {
if (properties == null || properties.isEmpty()) {
throw new IllegalArgumentException("You have to provide at least one property to sort by!");
}
this.orders = new ArrayList<Order>(properties.size());
for (String property : properties) {
this.orders.add(new Order(direction, property));
}
}
暂时还不清楚,下次有机会补上,反正就是传一个排序的方式,和一个待排序的List,然后可以返回一个排好序的包装过的Sort对象
然后调用代理的findAll()方法,默认传入了上一步的Sort对象
4.web层
先将第一个controller,用来进行页面跳转的,AdminPageController
@Controller
public class AdminPageController {
@GetMapping(value = "/admin")
public String admin() {
return "redirect:admin_category_list";
}
@GetMapping(value = "/admin_category_list")
public String listCategory() {
return "admin/listCategory";
}
}
这里的redirect时客户端跳转的意思,这里有个小知识点,另外一个则是服务器跳转
差别可以参考这一篇博客参考
这里的话,说一句个人的理解,第一个客户端跳转一般是用于重定向,第二个跳转,转到指定的页面
第二个controller
@RestController
public class CategoryController {
@Autowired
CategoryService categoryService;
@GetMapping("/categories")
public List<Category> list() {
return categoryService.list();
}
}
autowired关系就不用我说了,dao->service->controller
这一个controller是为了完成restful请求,所有返回结果都会直接被序列化为json的格式,所以在类的开头用了RestController注解,这个注解其实就是
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
String value() default "";
}
两个注解@Controller和@ResponseBody
调用service层的方法,也没啥好说的
5.异常处理
@Configuration
public class CORSConfiguration extends WebMvcConfigurerAdapter{
@Override
public void addCorsMappings(CorsRegistry registry) {
//所有请求都允许跨域
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
(1) @Configuration注解
(2) 继承WebMvcConfigurationAdapter类,重写addCorsMappings()方法,实现对所有请求的拦截
6.全局异常处理
@RestController
@ControllerAdvice
public class GloabalExceptionHandler {
@ExceptionHandler(value = Exception.class)
public String defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
e.printStackTrace();
Class constraintViolationException = Class.forName("org.hibernate.exception.ConstraintViolationException");
if(null!=e.getCause() && constraintViolationException==e.getCause().getClass()) {
return "违反了约束,多半是外键约束";
}
return e.getMessage();
}
}
这个类后面有机会再说
7. 讲解一下listCategory.html页面
这里主要讲thymeleaf语法和Vue的数据绑定过程
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:include="include/admin/adminHeader::html('分类管理')">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:replace="include/admin/adminNavigator::html"></div>
<script>
$(function () {
var data4Vue = {
uri: 'categories',
beans: []
};
//ViewModel
var vue = new Vue({
el: '#workingArea',
data: data4Vue,
mounted:function () {
//mounted 表示这个Vue被加载成功了
this.list();
},
methods: {
list:function () {
var url = this.uri;
axios.get(url).then(function (response) {
vue.beans = response.data;
});
}
}
});
});
</script>
<div id="workingArea" >
<h1 class="label label-info" >分类管理</h1>
<br>
<br>
<div class="listDataTableDiv">
<table class="table table-striped table-bordered table-hover table-condensed">
<thead>
<tr class="success">
<th>ID</th>
<th>图片</th>
<th>分类名称</th>
<th>属性管理</th>
<th>产品管理</th>
<th>编辑</th>
<th>删除</th>
</tr>
</thead>
<tbody>
<tr v-for="bean in beans ">
<td>{{bean.id}}</td>
<td>
<img height="40px" :src="'img/category/'+bean.id+'.jpg'">
</td>
<td>
{{bean.name}}
</td>
<td>
<a :href="'admin_property_list?cid=' + bean.id "><span class="glyphicon glyphicon-th-list"></span></a>
</td>
<td>
<a :href="'admin_product_list?cid=' + bean.id "><span class="glyphicon glyphicon-shopping-cart"></span></a>
</td>
<td>
<a :href="'admin_category_edit?id=' + bean.id "><span class="glyphicon glyphicon-edit"></span></a>
</td>
<td>
<a href="#nowhere" @click="deleteBean(bean.id)"><span class=" glyphicon glyphicon-trash"></span></a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div th:replace="include/admin/adminFooter::html"></div>
</body>
</html>
(1) thymeleaf部分
<div th:replace="include::footer1" ></div>
<div th:replace="include::footer2(2015,2018)" ></div>
前者是不带参数的引入其他页面,第二个是带参数的
<html xmlns:th="http://www.thymeleaf.org">
<footer th:fragment="footer1">
<p >All Rights Reserved</p>
</footer>
<footer th:fragment="footer2(start,now)">
<p th:text="|${start} - ${now} All Rights Reserved|"></p>
</footer>
</html>
这是被引入部分,用<footer>标签中的th:fragment属性标记
第一个参数是html文件名(相对路径?),第二个是被引入标签名,后面也可以跟参数
(2).Vue
<script>
$(function () {
var data4Vue = {
uri: 'categories',
beans: []
};
//ViewModel
var vue = new Vue({
el: '#workingArea',
data: data4Vue,
mounted:function () {
//mounted 表示这个Vue被加载成功了
this.list();
},
methods: {
list:function () {
var url = this.uri;
axios.get(url).then(function (response) {
vue.beans = response.data;
});
}
}
});
});
</script>
预定义一个封装数据对象,data4Vue,然后创建一个vue对象,传入双向绑定的属性与数据,mouted是在加载成功后就会执行的方法,methods中方法list用axios,用get方法请求url,然后接收数据
<tr v-for="bean in beans ">
<td>{{bean.id}}</td>
<td>
<img height="40px" :src="'img/category/'+bean.id+'.jpg'">
</td>
<td>
{{bean.name}}
</td>
</tr>
然后通过v-for遍历显示beans中的各个bean,渲染在页面上
谢谢观看,初学记录,请多多指正