天猫项目(1)分类管理之查询功能

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,渲染在页面上

 

谢谢观看,初学记录,请多多指正

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值