8-17项目总结

一,什么是SpringDataJpa
咱们要集成三大框架(Spring+SpringMVC+SpringDataJpa)



  4.0.0

  cn.itsource
  yxb
  1.0-SNAPSHOT

  
    UTF-8
    4.2.5.RELEASE
    4.3.8.Final
    1.9.0.RELEASE
    2.5.0
    1.6.1
  
  
    
    
      org.springframework
      spring-core
      ${org.springframework.version}
    
    
      org.springframework
      spring-context
      ${org.springframework.version}
    
    
      org.springframework
      spring-context-support
      ${org.springframework.version}
    

    
      org.springframework
      spring-tx
      ${org.springframework.version}
    
    
      org.springframework
      spring-jdbc
      ${org.springframework.version}
    
    
      org.springframework
      spring-orm
      ${org.springframework.version}
    
    
      org.springframework
      spring-aop
      ${org.springframework.version}
    
    
      org.springframework
      spring-test
      ${org.springframework.version}
      test
    
    
    
      org.springframework
      spring-web
      ${org.springframework.version}
    
    
      org.springframework
      spring-webmvc
      ${org.springframework.version}
    
    
    
      org.apache.commons
      commons-io
      1.3.2
    
    
    
      commons-fileupload
      commons-fileupload
      1.2.2
    
    
    
      com.fasterxml.jackson.core
      jackson-core
      ${com.fasterxml.jackson.version}
    
    
      com.fasterxml.jackson.core
      jackson-annotations
      ${com.fasterxml.jackson.version}
    
    
      com.fasterxml.jackson.core
      jackson-databind
      ${com.fasterxml.jackson.version}
    
    
    
      org.hibernate
      hibernate-core
      ${org.hibernate.version}
    
    
      org.hibernate
      hibernate-entitymanager
      ${org.hibernate.version}
    
    
    
      org.springframework.data
      spring-data-jpa
      ${spring-data-jpa.version}
    
    
    
      com.github.wenhao
      jpa-spec
      3.1.1
      
      
        
          *
          *
        
      
    

    
      commons-dbcp
      commons-dbcp
      1.2.2
    

    
      mysql
      mysql-connector-java
      5.1.6
    

    
      org.apache.commons
      commons-lang3
      3.5
    
    
    
      junit
      junit
      4.12
      test
    
    
      javax.servlet
      javax.servlet-api
      3.1.0
      
      provided
    
    
    
      org.slf4j
      slf4j-api
      ${org.slf4j.version}
    
    
      org.slf4j
      slf4j-log4j12
      ${org.slf4j.version}
      runtime
    
    
      log4j
      log4j
      1.2.14
    
    
    
      org.apache.velocity
      velocity
      1.6
    
  
   
      org.apache.shiro
      shiro-all
      1.4.0
      pom
  
    
    
      org.apache.shiro
      shiro-spring
      1.4.0
    
    
    
      org.apache.poi
      poi
      3.11
    
    
      org.apache.poi
      poi-ooxml
      3.11
    
    
    
    
      net.coobird
      thumbnailator
      0.4.6
    
    
    
      quartz
      quartz
      1.5.2
    
    
    
      javax.mail
      mail
      1.4.1
    
  

  
    yxb
    
      
        org.apache.maven.plugins
        maven-compiler-plugin
        
          1.8
          1.8
        
      
      
        org.mortbay.jetty
        jetty-maven-plugin
        8.1.15.v20140411
        
          9966
          foo
          
            /
          
        
      
    
  

二,SpringDataJpa的基本使用(掌握)
抽取id

@MappedSuperclass
public class BaseDomain {
    @Id
    @GeneratedValue
    public Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

抽取查询方法
BaseQuery公共查询对象,完成分页查询和排序

public abstract class BaseQuery {
    //当前页数
    private Integer currentPage=1;
    //每页条数
    private Integer pageSize=10;
    //排序字段
    private String orderByName;
    //排序类型默认 降序
    private String orderByType="DESC";
    public Integer getJpaPage(){
        return currentPage -1;
    }

    public Integer getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(Integer currentPage) {
        this.currentPage = currentPage;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public String getOrderByName() {
        return orderByName;
    }

    public void setOrderByName(String orderByName) {
        this.orderByName = orderByName;
    }

    public String getOrderByType() {
        return orderByType;
    }

    public void setOrderByType(String orderByType) {
        this.orderByType = orderByType;
    }
    //排序方法,设置需要排序才排序,不需要就不排序
    public Sort createSort(){
        Sort sort = null;
        if (orderByName!=null){
            //三目运算
            Sort.Direction type ="ASC".equals(orderByType.toUpperCase())?Sort.Direction.ASC:Sort.Direction.DESC;
            //组装sort
            sort = new Sort(type,orderByName);
        }
        return sort;
    }


    //该方法定义成抽象的目的,让子类都必须覆写该方法
    public abstract Specification createSpecification();
}

三,EmployeeRepository extends JpaRepository

//想通过员工的名称来查询员工 -- 如果按照一定的规范来写 底层就会解析完成
    List findEmployeeByUsername(String username);
    //like模糊查询
    List findEmployeeByUsernameLike(String username);
    //查询数据--Query注解查询
    @Query("select o from Employee o where o.username like ?1")
    List findEmpByUsername(String username);
    //根据顺序查询
    @Query("select o from Employee o where o.username like ?1 and o.email like ?2")
    List query02(String username,String emial);
    //根据名称来查询
    @Query("select o from Employee o where  o.username like :username and o.email like :email")
    List query03(@Param("username") String username1, @Param("email")String email1);
    //对原生sql语句
    @Query(value="select count(*) from employee ",nativeQuery=true)
    Long query04();

还可以继承多个接口

public interface EmployeeRepository1 extends JpaRepository,
        JpaSpecificationExecutor {
}

四,各种CRUD ,分页查询,高级搜索,

CRUD

 @Autowired
    private EmployeeRepository employeeRepository;

    //查询所有
    @Test
    public void testFindAll() throws Exception{
        List employees = employeeRepository.findAll();
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    //批量查询
    @Test
    public void testFindAll1() throws Exception{
        List list = Arrays.asList(55L,66L,77L);
        List employees = employeeRepository.findAll(list);
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
     @Autowired
    private EmployeeRepository employeeRepository;
    //查询所有
    @Test
    public void testJpa() throws Exception{
        List lists = employeeRepository.findAll();
        System.out.println(employeeRepository.getClass());
        for (Employee employee :lists ) {
            System.out.println(employee);
        }
    }


    @Test
    public void testfindAll() throws Exception{
        //表示多条查询查询25,26,27
        List lists = Arrays.asList(25L,26L,27L);
        List list = employeeRepository.findAll(lists);
        for (Employee o : list) {
            System.out.println(o);
        }
    }
    //查询一条数据
    @Test
    public void testFindOne() throws Exception{
        Employee employee = employeeRepository.findOne(6L);
        System.out.println(employee);
    }

    //保存
    @Test
    public void testsave() throws Exception{
        Employee employee = new Employee();
        employee.setUsername("公鸡");
        employee.setPassword("傻逼");
        employee.setAge(22);
        employeeRepository.save(employee);
    }
    //修改  如果有id 就修改 没有id 就新增
    @Test
    public void testUpdate() throws Exception{
        Employee employee = new Employee();
        employee.setId(275L);
        employee.setUsername("大鸡鸡");
        employee.setPassword("大傻逼");
        employee.setAge(18);
        employeeRepository.save(employee);
    }

    //删除
    @Test
    public void testDelete() throws Exception{
        employeeRepository.delete(275L);
    }

    @Test
    public void testDeleteInBatch() throws Exception{
        //指定删除两条
        List list = employeeRepository.findAll(Arrays.asList(272L, 273L));
        employeeRepository.deleteInBatch(list);
    }
    //总条数
    @Test
    public void testCount() throws Exception{
        System.out.println(employeeRepository.count());
    }

JpaSpecificationExecutor

@Autowired
    private EmployeeRepository1 employeeRepository1;
    @Test
    public void testSpec1() throws Exception{

        EmployeeQuery employeeQuery = new EmployeeQuery();
        employeeQuery.setUsername("呵呵");
        employeeQuery.setAge(234);
        Specification spe = Specifications.and().
                like(StringUtils.isNotBlank(employeeQuery.getUsername()),
                        "username", "%" + employeeQuery.getUsername() + "%")
                .gt(employeeQuery.getAge() != null, "age", employeeQuery.getAge())
                .build();
        //排序
        Sort sort = null;
        if(employeeQuery.getOrderByName()!= null){
            String orderByName = employeeQuery.getOrderByName();
            Sort.Direction direction = null;
            if(employeeQuery.getOrderByType().equals("DESC")){
                direction = Sort.Direction.DESC;
            }else{
                direction = Sort.Direction.ASC;
            }
            //组装Sort
            sort =new Sort(direction,orderByName);
        }
        //分页
        Pageable pageable = new PageRequest(employeeQuery.getJpaPage(), employeeQuery.getPageSize(), sort);
        Page employees = employeeRepository1.findAll(spe, pageable);
        for (Employee employee : employees) {
            System.out.println(employee);
        }

    }

    @Test
    public void testSpec2() throws Exception{
        EmployeeQuery employeeQuery = new EmployeeQuery();
        employeeQuery.setUsername("1");
        employeeQuery.setAge(18);
        Specification spec = employeeQuery.createSpecification();
        Sort sort = employeeQuery.createSort();
        Pageable pageable = new PageRequest(employeeQuery.getJpaPage(), employeeQuery.getPageSize(), sort);
        Page lists = employeeRepository1.findAll(spec, pageable);
        for (Employee employee : lists) {
            System.out.println(employee);
        }
    }

Query的抽取

@Autowired
    private EmployeeRepository employeeRepository;

    //按照规范查询
    @Test
    public void testQuery() throws Exception{
        List employees = employeeRepository.findEmployeeByUsername("acac");
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }

    //按照规范查询
    @Test
    public void testQuery1() throws Exception{
        //模糊查询
        List employees = employeeRepository.findEmployeeByUsernameLike("%bb%");
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }

    //Query注解查询
    @Test
    public void testQuery2() throws Exception{
        List emps= employeeRepository.findEmpByUsername("%bbbbbb%");
        for (Employee emp : emps) {
            System.out.println(emp);
        }
    }
    //根据顺序来查询
    @Test
    public void testQuery3() throws Exception{
        //多条件查询
        List emps= employeeRepository.query02("%cc%","%33%");
        for (Employee emp : emps) {
            System.out.println(emp);
        }
    }


    @Test
    public void testQuery4() throws Exception{
        List emps= employeeRepository.query03("b","%2%");
        for (Employee emp : emps) {
            System.out.println(emp);
        }
    }

    @Test
    public void testQuery5() throws Exception{
        System.out.println(employeeRepository.query04());

    }

springdatajpa的扩展–抽取

抽取一个BaseRepository – 写三个方法

@NoRepositoryBean
public interface BaseRepository extends JpaRepository, JpaSpecificationExecutor {

    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);

    //根据Query拿到对应的所有数据(不分页)
    List findByQuery(BaseQuery baseQuery);

    //根据jpql与对应的参数拿到数据
    List findByJpql(String jpql,Object... values);


}

然后实现BaseRepositoryImpl

public class BaseRepositoryImpl extends SimpleJpaRepository
        implements BaseRepository  {
    //让spring把entityManager给我注入过来 --factoryBean
    private final EntityManager entityManager;

    //必需要实现父类的这个构造器
    public BaseRepositoryImpl(Class domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    //分页查询的方法
    @Override
    public Page  findPageByQuery(BaseQuery baseQuery) {
        //得到Sort
        Sort sort = baseQuery.createSort();
        //条件
        Specification spec = baseQuery.createSpecification();
        //分页
        Pageable pageable = new PageRequest(baseQuery.getJpaPage(),baseQuery.getPageSize() , sort);
        //查询
        Page page = super.findAll(spec,pageable);
        return page;

    }
    //不分页
    @Override
    public List findByQuery(BaseQuery baseQuery) {
        Sort sort = baseQuery.createSort();
        Specification specs = baseQuery.createSpecification();
        //条件和排序
        List list = super.findAll(specs,sort);
        return list;
    }

    //select o from Employee o where o.username=? and o.email=?
    //xxx [email protected] 2
    @Override
    public List findByJpql(String jpql, Object... values) {
        //得到query对象
        Query query = entityManager.createQuery(jpql);
        //设值
        for (int i = 0; i < values.length; i++) {
            query.setParameter(i+1,values[i] );
        }

        return query.getResultList();
    }

然后管理起来自己用

二,创建web前端结构
完成Service层
创建IBaseService

public interface IBaseService {
    //新增和修改
    void save(T t);

    //删除 --Long
    void delete(ID id);

    //查询
    T findOne(ID id);

    //查询所有
    List findAll();

    //根据Query拿到分页对象(分页)
    Page findPageByQuery(BaseQuery baseQuery);

    //根据Query拿到对应的所有数据(不分页)
    List findByQuery(BaseQuery baseQuery);

    //根据jpql与对应的参数拿到数据
    List findByJpql(String jpql,Object... values);
}

创建BaseServiceImpl

@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class BaseServiceImpl implements IBaseService {

    //spring 4之后 支持泛型的注解
    @Autowired
    private BaseRepository baseRepository;

    @Override
    @Transactional
    public void save(T t) {
        baseRepository.save(t);
    }

    @Override
    @Transactional
    public void delete(ID id) {
        baseRepository.delete(id);
    }

    @Override
    public T findOne(ID id) {
        return baseRepository.findOne(id);
    }

    @Override
    public List findAll() {
        return baseRepository.findAll();
    }

    @Override
    public Page findPageByQuery(BaseQuery baseQuery) {
        return baseRepository.findPageByQuery(baseQuery);
    }

    @Override
    public List findByQuery(BaseQuery baseQuery) {
        return baseRepository.findByQuery(baseQuery);
    }

    @Override
    public List findByJpql(String jpql, Object... values) {
        return baseRepository.findByJpql(jpql,values);
    }
}

创建IEmployeeService

public interface IEmployeeService extends IBaseService {
}

创建EmployeeServiceImpl

@Service
public class EmployeeServiceImpl extends BaseServiceImpl
        implements IEmployeeService {
}

配置applicationContext-mvc.xml



    
    
    
    
    
    
    
        
            
                
                    
                        application/json; charset=UTF-8
                        application/x-www-form-urlencoded; charset=UTF-8
                    
                
                
                
                    
                
            
        
    

    
    
        
        
        
        
        
        
    

    
    
        
        
            1048576
        
    

配置web.xml






完成Controller层

@Controller
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    private IEmployeeService employeeService;

    @RequestMapping("/index")
    public String index() {
        //根据配置,这里会跳到/WEB-INF/views/employee/employee.jsp页面
        return "employee/employee";
    }
    @RequestMapping("/list")
    @ResponseBody
    public List list(){
        return employeeService.findAll();
    }

}

三,完成员工页面前端展示和分页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@include file="/WEB-INF/views/head.jsp"%>



    Title
    


    
    
头像 用户名 密码 邮件 年龄 部门名称
用户名: 邮件: 部门 : 查找

解决懒加载问题


    openEntity
    org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter


    openEntity
    /*

public class CustomMapper extends ObjectMapper {
    public CustomMapper() {
        this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 设置 SerializationFeature.FAIL_ON_EMPTY_BEANS 为 false 对null的bean 不做序列化
        this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }
}

加入高级查询条件
UtilController

@Controller
@RequestMapping("/util")
public class UtilController {
    //注入部门信息
    @Autowired
    private IDepartmentService departmentService;

    //departmentList
    @RequestMapping("/departmentList")
    @ResponseBody
    public List queryDepartmentList(){
        return departmentService.findAll();
    }
}

$(function(){
    //定义form表单
    var searchForm = $("#searchForm");
    var employeeGrid = $("#employeeGrid");

    //绑定事件 easyui 第二天的时候
    $("a[data-method]").on('click',function(){
       //获取 data-method属性 
        var methodName = $(this).data("method");
        //动态调用方法 itsource["seacher"]
        itsource[methodName]();
    })
    //对象
    var itsource = {
        search:function(){
          //怎么完成高级查询 jquery.jdirk.js 这个方法 这是jquery扩展方法
            //该方法返回一个 JSON Object,返回对象中的每个数据都表示一个表单控件值。
            var param = searchForm.serializeObject();
            //发送查询数据库 --加载表格 发送请求 /employee/page
            employeeGrid.datagrid('load',param);
        },
        add:function(){
            alert(1);
        }
    }

public class EmployeeQuery extends BaseQuery{

    /**
     * username	admin
     * email	[email protected]
     * departmentId	1
     */
    //自身条件
    private String username;
    private String email;
    private Integer age;

    private Integer departmentId;


    public Integer getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(Integer departmentId) {
        this.departmentId = departmentId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
    //抽取查询
    @Override
    public Specification createSpecification() {
        Specification spe = Specifications.and().
                like(StringUtils.isNotBlank(username), "username", "%" + username + "%")
                .like(StringUtils.isNotBlank(email), "email", "%" + email + "%")
                .eq(departmentId!=null,"department.id",departmentId)
                .gt(age != null, "age", age)
                .build();

        return spe;
    }
}

一,智能销售CRUD

后台

@Controller
@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    private IEmployeeService employeeService;
    //加载页面
    @RequestMapping("/index")
    public String index(){
        return "employee";
    }

    //分页处理
    @RequestMapping("/page")
    @ResponseBody
    public UiPage page(EmployeeQuery employeeQuery){

        Page page = employeeService.findPageByQuery(employeeQuery);
        UiPage uipage = new UiPage(page);
        return uipage;
    }

    //方法 delete
    @RequestMapping("/delete")
    @ResponseBody
    public Map delete(Long id){
        Map mp = new HashMap();
        try {
            employeeService.delete(id);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }

    //保存方法-- 修改和新增保存
    @RequestMapping("/save")
    @ResponseBody
    public Map save(Employee employee){
        Map mp = new HashMap();
        try {
            employeeService.save(employee);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }

    @RequestMapping("/update")
    @ResponseBody
    public Map update(@ModelAttribute("editEmployee") Employee employee){
        Map mp = new HashMap();
        try {
            employeeService.save(employee);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }

    //去重
    @RequestMapping("/checkUsername")
    @ResponseBody
    public boolean checkUsername(String username,Long id){
        if(id != null && !"".equals(id)){
            //修改
            Employee employee = employeeService.findOne(id);
            String username_db = employee.getUsername();
            if(username.equals(username_db)){
                return true;
            }
        }

        return employeeService.checkUsername(username);
    }


    //删除方法
    @ModelAttribute("editEmployee")
    public Employee beforeEdit(Long id,String cmd){
        Employee employee = null;
        if("update".equals(cmd) && id != null && !"".equals(id) ){
            employee = employeeService.findOne(id);
            employee.setDepartment(null);
        }
        return employee;
    }

}

前台处理

/表格数据格式化
function formatObj(value){
    if(value){
        return value.name;
    }
}
//formatImage头像格式化
function formatImage(value){
   if(value){
       return "没有图片"
   }
}

//自己去扩展easyui验证的功能
$.extend($.fn.validatebox.defaults.rules, {
    equals: {
        validator: function(value,param){

            return value == $(param[0]).val();
        },
        message: '密码不匹配.'
    }
});

//扩展用户名是否重复的功能
$.extend($.fn.validatebox.defaults.rules, {
    checkUsername: {
        validator: function(value,param){
            //当然输入框value 和数据库的username进行比较
            //发送ajax请求 --异步(ajax同步)
            var id = $("#employeeId").val();
           var result =  $.ajax({
                type: "POST",
                url: "/employee/checkUsername",
                data: "username="+value+"&id="+id,
                async: false //同步
            }).responseText;

            return result == 'true';
        },
        message: '用户名重复了.'
    }
});


$(function(){
    //定义form表单
    var searchForm = $("#searchForm");
    var employeeGrid = $("#employeeGrid");
    //获取employeeDialog
    var employeeDialog = $("#employeeDialog");
    //定义表单新增的form
    var employeeForm = $("#employeeForm");

    //绑定事件 easyui 第二天的时候
    $("a[data-method]").on('click',function(){
       //获取 data-method属性 
        var methodName = $(this).data("method");

        itsource[methodName]();
    });
    //对象
    var itsource = {
        search:function(){

            var param = searchForm.serializeObject();

            employeeGrid.datagrid('load',param);
        },
        add:function(){
            //隐藏数据 display:none
            $("tr[data-save]").show();
            //取消密码验证
            $("*[data-save] input").validatebox("enableValidation");
            //清空表单
            employeeForm.form('clear');
            //新增 --弹出一个对话框--装一个表单
            employeeDialog.dialog('center').dialog('open');

        },
        edit:function(){
            //选择一条数据进行修改
            var row = employeeGrid.datagrid('getSelected');
            if(row){
                //隐藏数据 display:none
                $("tr[data-save]").hide();
                //取消密码验证
                $("*[data-save] input").validatebox("disableValidation");
                //部门回显
                if(row.department){
                  row["department.id"] = row.department.id;
                }
                //修改 -- 回显示数据
                employeeForm.form('load',row);
            }else{
                //提示用户
                $.messager.alert('温馨提示:','请修改其中一条','info');
                return;
            }
          //弹出对话框
            employeeDialog.dialog('center').dialog('open');
        },
        del:function(){
            //判断表格里面是否选中得数据
            var row = employeeGrid.datagrid('getSelected');
            if(row){
                //是否确认要删除数据
                $.messager.confirm('温馨提示','是否要删除?',function(value){
                    if(value){
                        //获取id值

                        //发送ajax到后台进行删除数据
                        $.get('/employee/delete',{"id":row.id},function(data){
                            //返回json对象
                            if(data.success){
                                $.messager.alert('温馨提示:','删除成功','info');
                                //重新加载数据
                                employeeGrid.datagrid('reload');
                            }else{
                                $.messager.alert('温馨提示:','删除失败'+data.msg,'error');
                            }
                        });
                    }
                })

            }else{
                //提示用户
                $.messager.alert('温馨提示:','选中一条进行删除','info');
                return;
            }

        },
        save:function(){
            var url = "/employee/save";
            //获取隐藏域里面id值
            var id = $("#employeeId").val();
            if(id){
                url = "/employee/update?cmd=update"
            }
            //保存方法 --提交表单的数据到后台
            employeeForm.form('submit', {
                    url:url,
                    onSubmit: function(){
                        // 提交之前的验证
                       return employeeForm.form('validate');
                     },
                success:function(data){
                        //字符串 转换成json对象
                      var dataJson =  $.parseJSON(data);
                      if(dataJson.success){
                          $.messager.alert('温馨提示:','操作成功','info');
                          //重新加载数据
                          employeeGrid.datagrid('reload');
                          //关闭对话框
                          employeeDialog.dialog('close');
                      }else{
                          $.messager.alert('温馨提示:','保存失败'+dataJson.msg,'error');
                          employeeDialog.dialog('close');
                      }
                }
            });
        }
    }



})

二.模板技术(freemarker-velocity)

模板技术怎样输出数据
数据+模板(html文件,vm文件,ftl文件)=输出文本
Velocity模板技术可以实现的功能
动态页面静态化:xxx.html --动态页面页面 静态化
pom.xml:添加jar文件



	org.apache.velocity
	velocity
	1.6

测试Velocity功能

public class VelocityTest {
    @Test
    public void testVelocity01() throws Exception {
        //创建模板应用上下文
        VelocityContext context = new VelocityContext();
        context.put("msg", "花好月圆");
        //拿到相应的模板(需要设置好编码)
        Template template = Velocity.getTemplate("temptest/hello.html","UTF-8");
        //准备输出流
        StringWriter writer = new StringWriter();
        template.merge(context, writer);
        System.out.println(writer);
    }


    @Test
    public void testVelocity02() throws Exception {
        //创建模板应用上下文
        VelocityContext context = new VelocityContext();
        context.put("msg", "男上加男");
        //拿到相应的模板(需要设置好编码)
        Template template = Velocity.getTemplate("temptest/hello.html","UTF-8");
        //准备输出流
        File file = new File("temptest/helloNew.html");
        FileWriter writer = new FileWriter(file);
        template.merge(context, writer);
        writer.close();
    }

}

三,代码生成器(手动写代码生成代码生成器)

一.开发步骤
1.准备模板(把每个模块需要改的地方确定好)
2.确定所有模板的生成顺序
3.确定所有模板的生成位置
4.确定要生成的基本功能的domain(Dept)
5.根据Domain名称与模板结合,在相应位置生成文件
6.解决如果父文件夹不存在的问题
7.解决如果文件已经存在的问题
8.排错(有错先改模板)
按照课件走,

@Test
public void testCreate() throws Exception{
    //创建模板应用上下文
    VelocityContext context = new VelocityContext();
    //一.遍历所有的Domain
    for (int i = 0; i < domains.length; i++) {
        //1.1拿到大写的domain
        String domainBig = domains[i];//Dept
        //1.2拿到小写的domain  //dept
        String domainSmall = domainBig.substring(0,1).toLowerCase() + domainBig.substring(1);
        //System.out.println(domainBig);
        //System.out.println(domainSmall);
        //1.3设置上下文的替换名称
        context.put("Domain",domainBig);
        context.put("domain",domainSmall);
        //二.遍历所有的路径
        for (int j = 0; j < paths.length; j++) {
            //2.1拿到相应的路径
            String path =paths[j];
            //2.2拿到相应的模板名称
            String tempName = tempNames[j];
            //2.3拼接回我们需要的位置文件
            String realPath = (path + tempName).replaceAll("Domain",domainBig).replaceAll("domain",domainSmall);

            //三.准备相应文件与模板进行组合
            //3.1准备相应的文件(要生成的文件)
            File file = new File(realPath);
            //  如果父文件不存在,我们创建一个
            File parentFile = file.getParentFile();
            if(!parentFile.exists()){
                parentFile.mkdirs();
            }
            //3.2拿到相应的模板(需要设置好编码)
            Template template = Velocity.getTemplate("template/"+tempName,"UTF-8");
            FileWriter writer = new FileWriter(file);
            template.merge(context, writer);
            writer.close();
        }
    }
}

easycode

支持的数据库类型
因为是基于Database Tool开发,所有Database Tool支持的数据库都是支持的。
包括如下数据库:
1.MySQL
2.SQL Server
3.Oracle
4.PostgreSQL
5.Sqlite
6.Sybase
7.Derby
8.DB2
9.HSQLDB
10.H2
安装按照课件和老师讲的走

代码生成器模板

domain

##引入宏定义
$!define
##拿到首字母小写的表单
#set($lowerTableInfo = $tool.firstLowerCase($!{tableInfo.name}))
##使用宏定义设置回调(保存位置与文件后缀)
##注意:为了路径,我现在都从main的位置开始
#save("/main/java/cn/itsource/zx/domain", ".java")

##使用宏定义设置包后缀
#setPackageSuffix("domain")

##使用全局变量实现默认包导入
$!autoImport
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;

##使用宏定义实现类注释信息
#tableComment("实体类")
@Entity
@Table(name="$!{lowerTableInfo}")
public class $!{tableInfo.name} extends BaseDomain {

##实现列进行排除
#set($temp = $tool.newHashSet("id"))
#foreach($item in $temp)
    #set($newList = $tool.newArrayList())
    #foreach($column in $tableInfo.fullColumn)
        #if($column.name!=$item)
        ##带有反回值的方法调用时使用$tool.call来消除返回值
            $tool.call($newList.add($column))
        #end
    #end
##重新保存
    $tableInfo.setFullColumn($newList)
#end

#foreach($column in $tableInfo.fullColumn)
    #if(${column.comment})//${column.comment}#end
    private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end


#foreach($column in $tableInfo.fullColumn)
##使用宏定义实现get,set方法
    #getSetMethod($column)
#end

}

Query查询
##定义初始变量
#set($tableName = t o o l . a p p e n d ( tool.append( tool.append(tableInfo.name, “Query”))
##设置文件名
! c a l l b a c k . s e t F i l e N a m e ( !callback.setFileName( !callback.setFileName(tool.append($tableName, “.java”))
##设置文件保存的位置(依然是从src开始)
! c a l l b a c k . s e t S a v e P a t h ( !callback.setSavePath( !callback.setSavePath(tool.append($tableInfo.savePath, “/main/java/cn/itsource/zx/query”))

##拿到首字母小写的表单
#set($lowerTableInfo = t o o l . f i r s t L o w e r C a s e ( tool.firstLowerCase( tool.firstLowerCase(!{tableInfo.name}))

##引入相应的包
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}query;
##使用全局变量实现默认包导入
! a u t o I m p o r t i m p o r t c n . i t s o u r c e . z x . d o m a i n . !autoImport import cn.itsource.zx.domain. !autoImportimportcn.itsource.zx.domain.!{tableInfo.name};
import com.github.wenhao.jpa.Specifications;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;

public class KaTeX parse error: Expected '}', got '#' at position 45: …s BaseQuery { #̲#注:如果生成的表没有name…!{tableInfo.name}>and()
.like(StringUtils.isNotBlank(name),“name”, “%”+name+"%")
.build();
}

public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

}
Repository数据层

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "Repository"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/main/java/cn/itsource/zx/repository"))

##拿到首字母小写的表单
#set($lowerTableInfo = $tool.firstLowerCase($!{tableInfo.name}))

##引入相应的包
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}repository;
import cn.itsource.zx.domain.$!{tableInfo.name};

public interface $!{tableInfo.name}Repository extends BaseRepository<$!{tableInfo.name},Long>{

}

IService业务层接口

##定义初始变量
#set($tableName = $tool.append("I",$tableInfo.name, "Service"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/main/java/cn/itsource/zx/service"))

##拿到首字母小写的表单
#set($lowerTableInfo = $tool.firstLowerCase($!{tableInfo.name}))

##引入相应的包
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service;

import cn.itsource.zx.domain.$!{tableInfo.name};

public interface I$!{tableInfo.name}Service extends IBaseService<$!{tableInfo.name},Long> {

}

Service

##定义初始变量
#set($tableName = $tool.append($tableInfo.name, "ServiceImpl"))
##设置回调
$!callback.setFileName($tool.append($tableName, ".java"))
$!callback.setSavePath($tool.append($tableInfo.savePath, "/main/java/cn/itsource/zx/service/impl"))

##拿到首字母小写的表单
#set($lowerTableInfo = $tool.firstLowerCase($!{tableInfo.name}))

##引入相应的包
#if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl;

import cn.itsource.zx.domain.$!{tableInfo.name};
import cn.itsource.zx.repository.$!{tableInfo.name}Repository;
import cn.itsource.zx.service.I$!{tableInfo.name}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class $!{tableInfo.name}ServiceImpl extends BaseServiceImpl<$!{tableInfo.name},Long> implements I$!{tableInfo.name}Service {

    @Autowired
    private $!{tableInfo.name}Repository $!{lowerTableInfo}Repository};
    
}

一,shiro

Apache Shiro是一个强大且易用的架,有身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
Spring security 重量级安全框架Java安全框
Apache Shiro轻量级安全框架
Shiro:是一个apache的安全框架,还有spring security;
Shiro:能做:身份认证(登录)authentication,授权authorization,密码学,会话管理。
应用–》Subject(当前用户)—》Security Mananger管理–》Realm----》db
导入jar


    
        org.apache.shiro
        shiro-core
        1.4.0
    
    
        commons-logging
        commons-logging
        1.2
    
    
        junit
        junit
        4.12
    

[users]
# 用户 'root' 密码是 'secret' and the 'admin' 角色
root = secret, admin
# 用户 'guest' 密码 'guest' 和'guest'角色
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# 用户 'darkhelmet' with password 'ludicrousspeed' and 角色 'darklord' and 'schwartz'
darkhelmet = 123, darklord, schwartz
# 用户 'lonestarr' 密码 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# 这个 'schwartz' 角色 能干lightsaber下面的所有事情:
schwartz = lightsaber:*
# goodguy这个角色 能干winnebago下面的drive权限,操作eagle5这个资源 user:delete:5
goodguy = winnebago:drive:eagle5

测试

 @Test
    public void test() throws Exception{
        //填入路径到工厂对象中去
        Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //得到SecutiryManager 核心对象
        SecurityManager securityManager = factory.getInstance();
        //设置到shiro环境中去
        SecurityUtils.setSecurityManager(securityManager);
        //获得主体
        Subject subject = SecurityUtils.getSubject();
        //创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("darkhelmet", "123");
        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("该账号不存在");
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        }catch (AuthenticationException e) {
            e.printStackTrace();
            System.out.println("其他认证错误");
        }
        //角色判断
        if (subject.hasRole("admin")){
            System.out.println("这个角色有admin");
        }else{
            System.out.println("没有该角色");
        }
        //权限判断
        if (subject.isPermitted("lightsaber:*")){
            System.out.println("该角色有lightsaber权限");
        }else{
            System.out.println("没有权限");
        }
    }

自定义Realm

public class MyRealm extends AuthorizingRealm {
    //授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //得到用户名
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        //拿到权限去数据库查询
        Set role = getRoleByPrincipal(primaryPrincipal);
        //拿到角色去数据库查询
        Set permission = getPermissionByPrincipal(primaryPrincipal);


        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //设置角色
        simpleAuthorizationInfo.setRoles(role);
        //设置权限
        simpleAuthorizationInfo.setStringPermissions(permission);

        return simpleAuthorizationInfo;
    }

    //通过用户拿到角色
    private Set getRoleByPrincipal(String primaryPrincipal){
        Set roles = new HashSet();
        if("gongji".equals(primaryPrincipal)){
            roles.add("admin");
            return roles;
        }else{
            return null;
        }
    }
    //通过用户获取权限
    private Set getPermissionByPrincipal(String primaryPrincipal){
        Set permissions = new HashSet();
        if("gongji".equals(primaryPrincipal)){
            permissions.add("admin");
            return permissions;
        }else{
            return null;
        }
    }

    //身份认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //得到令牌
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        //主体
        Object principal = token.getPrincipal();
        System.out.println(principal);

        //获取用户名 zhangsan
        String username = token.getUsername();
        System.out.println(username);

        //通过用户名 去数据库查询数据 -- 查询用户的信息
        // 没有加密返回 String dbpwd= getPwdByUsername(username);
        String md5Pwd = getMD5PwdByUsername(username);
        //处理用户名问题 用户名是否存在的问题
        if(md5Pwd==null){
            //用户不存在
            return null;
        }
        //ByteSource
        ByteSource salt = ByteSource.Util.bytes("itsource");
        //下面进行密码的比对  shiro 底层它会自动进行比对 -- 处理密码问题
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, md5Pwd,salt, getName());

        return simpleAuthenticationInfo;
    }

    //通过用户名去拿到密码
    public String getPwdByUsername(String username){
        if("gongji".equals(username)){
            return "123";
        }else{
            return null;
        }
    }
    //加密返回密码
    public String getMD5PwdByUsername(String username){
        if("gongji".equals(username)){
            return "d5a3fedf6c59c2ecbe7f7a6c1a22da37";
        }else{
            return null;
        }
    }

    public static void main(String[] args) {
        //MD5 本身是不可破解 ..不可逆  网上看到破解方式 都是穷举把
        //(1)普通加密+202cb962ac59075b964b07152d234b70 -123
        SimpleHash simpleHash = new SimpleHash("MD5","123" );
        //(2)加密+加次数
        SimpleHash simpleHash1 = new SimpleHash("MD5","123",null,10 );
        //5371007260db2b98e3f7402395c45f28
        //(3)加密123 加盐 + itsource +加次数 --d5a3fedf6c59c2ecbe7f7a6c1a22da37 -- 最安全
        SimpleHash simpleHash2 = new SimpleHash("MD5","123","itsource",10 );
        System.out.println(simpleHash.toString());
        System.out.println(simpleHash1.toString());
        System.out.println(simpleHash2.toString());
    }
}

Shiro中密码加密

 @Test
    public void testDiyRealm() throws Exception{

        //创建自定义myRealm
        MyRealm myRealm  = new MyRealm();
        //得到SecutiryManager 核心对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        securityManager.setRealm(myRealm);
        //设置到shiro的环境里面 才能运行
        SecurityUtils.setSecurityManager(securityManager);
        //密码匹配器
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(10);
        //在realm设置匹配器
        myRealm.setCredentialsMatcher(matcher);

        //完成一些认证 拿到主体 -- 游客
        Subject subject = SecurityUtils.getSubject();

        //创建令牌
        UsernamePasswordToken token = new UsernamePasswordToken("gongji","123");
        try {
            subject.login(token);
            System.out.println("登陆成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误..");
        }catch (AuthenticationException e) {
            e.printStackTrace();
            System.out.println("其他认证错误");
        }
        System.out.println(subject);
        //判断角色 --shiro底层 自动找到myRealm 返回AuthorizationInfo 信息 进行判断比较
        if(subject.hasRole("admin")){
            System.out.println("豪哥有:admin角色");
        }
        //判断主题是否有权限
        if(subject.isPermitted("driver:xx")){
            System.out.println("公鸡可以开车");
        }



        subject.logout();//退出


    }

二,Shiro集成Spring

配置导包


 
    org.apache.shiro
    shiro-all
    1.4.0
    pom

  
  
    org.apache.shiro
    shiro-spring
    1.4.0
  

  shiroFilter
  org.springframework.web.filter.DelegatingFilterProxy
  
    targetFilterLifecycle
    true
  



  shiroFilter
  /*

三,Authentication(身份认证)和Authorizing(授权)

public class MyRealm extends AuthorizingRealm {

    //登陆认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
       
        //身份 username
        Object username = authenticationToken.getPrincipal();
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username1 = token.getUsername();

        //通过用户名得到密码
        String pwd = getPwdByUsername(username1);
        if(pwd == null){
            return null;
        }
        //添加颜值
        ByteSource salt = ByteSource.Util.bytes("itsource");
        //得到simpleAuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,pwd,salt,getName());


        return simpleAuthenticationInfo;
    }

    public String getPwdByUsername(String username){
        if("bb".equals(username)){
            return "607ca42819a4452f620bf721b7558c18";
        }else{
            return null;
        }
    }

    public static void main(String[] args) {
        SimpleHash simpleHash = new SimpleHash("MD5", "520520", "itsource", 10);
        System.out.println(simpleHash);
    }

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //得到主体/用户
        String username =(String)principalCollection.getPrimaryPrincipal();
        //根据用户 从数据库去拿到权限 加入到shiro里面
        Set permissions = new HashSet<>();
        if(username.equals("bb")){
            permissions.add("user:*");
            permissions.add("employee:*");
        }

        SimpleAuthorizationInfo simpleAuthorizationInfo  = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);

        //返回到shiro里面 就会进行权限的判断
        return simpleAuthorizationInfo;
    }
}

授权数据库查询

public class AisellFilterChainDefinitionMapBuilder {


    public Map buildFilterChaiDefinitionMap(){
        //map要顺序要求
        /**
         */

        Map mp = new LinkedHashMap();
        mp.put("/s/login.jsp","anon");
        mp.put("/login","anon");
        mp.put("/s/permission.jsp","perms[user:*]");
        mp.put("/**","authc");
        return mp;


    }
}

一,登录功能

把数据库里面的内容加密

public class MD5Util {
   // String algorithmName, Object source, Object salt, int hashIterations
    //设置盐值
    public static final String SALT = "itsource";
    //设置遍历次数
    public static final int HASHITERATIONS = 10;
    //传入一个字符串,返回一个md5编码的值
    public static String createMd5Str(String str){
        SimpleHash hash = new SimpleHash("MD5",str,SALT,HASHITERATIONS);
        return hash.toString();
    }
}
@Test
public void testUpdatePwd() throws Exception{
    List list = employeeService.findAll();
    for (Employee employee : list) {
        employee.setPassword(MD5Util.createMd5Str(employee.getPassword()));
        employeeService.save(employee); //注:save是添加与修改
    }
}

准备登陆页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    源码智销系统
    <%@ include file="/WEB-INF/views/head.jsp"%>
    


用户名:
密 码:
登陆 重置

修改applicationContext-shiro.xml

    
        
        
        
        
        
        
        

静态资源放行

  Map mp = new LinkedHashMap();
        mp.put("/login","anon");
        mp.put("*.js","anon");
        mp.put("*.css","anon");
        mp.put("/css/**","anon");
        mp.put("/js/**","anon");
        mp.put("/easyui/**","anon");
        mp.put("/images/**","anon");

        mp.put("/s/login.jsp","anon");

        mp.put("/s/permission.jsp","perms[user:*]");
        mp.put("/**","authc");
        return mp;

完成登陆功能

public class JpaRealm extends AuthorizingRealm {

    @Autowired
    private IEmployeeService employeeService;

    。。。

    //AuthenticationInfo:认证; 身份验证; 证明
    //登录的时候就会调用这个方法来做验证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //身份认证(用户名)
        // 1.拿到用户名
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
        String username = usernamePasswordToken.getUsername();
        // 2.根据用户名到数据库拿到用户
        Employee loginUser = employeeService.findByUsername(username);
        if(loginUser==null){
            return null; //该用户名不存在
        }
        //从数据库中拿到密码
        Object credentials = loginUser.getPassword();
        //加盐的数据
        ByteSource byteSource = ByteSource.Util.bytes("itsource");
        return new SimpleAuthenticationInfo(loginUser,credentials,byteSource,getName());
    }
}

json返回封装数据

public class JsonResult {
    //是否成功
    private boolean success = true;
    //消息
    private String msg ;

    public JsonResult() {
    }


    public JsonResult(boolean success, String msg) {
        this.success = success;
        this.msg = msg;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

登陆功能

 @RequestMapping(value = "/login",method = RequestMethod.POST)
       @ResponseBody
        public JsonResult login(String username, String password) {

           //得到主体
           Subject subject = SecurityUtils.getSubject();
           //判断改主体是否已经认证过
           if (!subject.isAuthenticated()) {
               //完成认证
               try {
                   UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                   subject.login(token);

               } catch (UnknownAccountException e) {
                   e.printStackTrace();
                   System.out.println("账号不存在");
                   return new JsonResult(false, "账号不存在");

               } catch (IncorrectCredentialsException e) {
                   e.printStackTrace();
                   System.out.println("密码错误");
                   return new JsonResult(false, "密码错误");
               } catch (AuthenticationException e) {
                   e.printStackTrace();
                   System.out.println("其他问题");
                   return new JsonResult(false, "其他问题");
               }


           }
           //表示成功
           return new JsonResult();

       }

       //注销
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "forward:/WEB-INF/views/login.jsp";
    }

二,权限domain部分

创建domain使用代码生成器完成

权限完善

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    permission管理
    <%@include file="/WEB-INF/views/head.jsp" %>
    



        <%-- --%>
    
权限名称 资源路径 描述 权限编号menuId
name:
url:
descs:
sn:
menuId:
添加
修改
删除

三,角色管理(页面功能)

名称: 编码:
名称 对应的资源 对象的权限
名称 对应的资源 对象的权限
role.js … //用户权限列表 var userPermissionGrid =$("#userPermissionGrid"); //所有权限列表 var allPermissionGrid =$("#allPermissionGrid"); … var itsource={ … //添加数据(弹出添加的模态框) add:function () { //如果有data-save属性,我们把它展示出来 $("*[data-save]").show(); //启动有data-save属性的input元素的验证功能 $("*[data-save] input").validatebox("enableValidation"); roleForm.form("clear");//清除数据 //弹出表单窗口 roleDialog.dialog("center").dialog('open'); //当前用户权限清空 userPermissionGrid.datagrid("loadData",[]); }, //修改数据(弹出修改的模态框) edit:function () { //选中了某一条数据才删除 var row = roleGrid.datagrid("getSelected"); if(row){ //隐藏有data-save属性的元素 $("*[data-save]").hide(); //禁用有data-save属性的input元素的验证功能 $("*[data-save] input").validatebox("disableValidation"); roleForm.form("clear");//清除数据 roleDialog.dialog("center").dialog('open'); //为form加载数据 roleForm.form("load",row); //单独解决权限的回显问题(注意,这里要准备一个新的权限,以免删除时出问题) var permissions = []; $.extend(permissions,row.permissions); userPermissionGrid.datagrid("loadData",permissions); }else{ $.messager.alert('提示信息','请选择一行再进行修改!','info'); } }, … //双击所有权限,把一个权限交给这个角色 addPermission:function(rowIndex, rowData){ //判断是否有重复的行 //1.拿到角色权限所有的行数据 var rows = userPermissionGrid.datagrid("getRows"); //2.遍历rows拿到每一个员工数据 for(var i=0;i

一,权限判断

拿到所有用户

 //登陆认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //身份 username
        Object username = authenticationToken.getPrincipal();
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username1 = token.getUsername();

        //通过用户名得到密码 admin 从数据库读取数据 --根据用户名去查询用户的方法

        Employee employee = employeeService.getEmployeeByUsername(username1);
        if(employee == null){
            return null;
        }
        System.out.println(employee.getPassword());
        //添加颜值
        ByteSource salt = ByteSource.Util.bytes("itsource");
        //得到simpleAuthenticationInfo
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(employee,employee.getPassword(),salt,getName());


        return simpleAuthenticationInfo;
    }

UserContext:设置与拿到当前登录用户
放入到session中去

//工具
public class UserContext {

    public static final String USER_IN_SESSION = "loginUser";

    //存入session
    public static void setUser(Employee loginUser){
        Subject subject = SecurityUtils.getSubject();
        subject.getSession().setAttribute(USER_IN_SESSION, loginUser);
    }

    //取出session
    public static Employee getUser(){
        Subject subject = SecurityUtils.getSubject();
        return (Employee) subject.getSession().getAttribute(USER_IN_SESSION);
    }
}

根据当前用户拿到当前用户对应的id


public interface IPermissionService extends IBaseService{

    //根据当前登录的用户 查询用户自己的权限
    public Set findPermissionsByLoginUser(Long id);

}

权限判断Ajax请求和自定义权限拦截器

public class AisellPermissionAuthorizationFilter extends PermissionsAuthorizationFilter {
    //Ctrl+o复写方法
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        //得到主体
        Subject subject = this.getSubject(request, response);
        //判断主体是否为空
        if(subject.getPrincipal()==null){
        //登录失败的操作
            this.saveRequestAndRedirectToLogin(request,response);
        }else {
            //如果拦截请求是ajax请求,就返回json处理 否者就返回页面

            HttpServletRequest req = (HttpServletRequest) request;

            HttpServletResponse resp =(HttpServletResponse) response;

            //获取请求头
            String header = req.getHeader("X-Requested-With");


            if ("XMLHttpRequest".equals(header)){
                //设置类型和编码

                resp.setContentType("text/json;charset=UTF-8");
                resp.getWriter().print("{\"success\":false,\"msg\":\"没有权限\"}");
            }else {
                //返回页面
                String unauthorizedUrl = this.getUnauthorizedUrl();
                if (StringUtils.hasText(unauthorizedUrl)) {
                    WebUtils.issueRedirect(request, response, unauthorizedUrl);
                } else {
                    WebUtils.toHttp(response).sendError(401);
                }
            }
        }


        return false;


    }

}

静态资源放行

public class AisellFilterChainDefinitionMapBuilder {
    //注入
    @Autowired
    private IPermissionService permissionService;


    public Map buildFilterChaiDefinitionMap(){
        //map要顺序要求
        /**
         */
        Map mp = new LinkedHashMap();
        mp.put("/login","anon");
        mp.put("*.js","anon");
        mp.put("*.css","anon");
        mp.put("/css/**","anon");
        mp.put("/js/**","anon");
        mp.put("/easyui/**","anon");
        mp.put("/images/**","anon");

        mp.put("/s/login.jsp","anon");

       //从数据库查询出来放入shiro不能写死
        List permissions = permissionService.findAll();
        //取出所有url和sn
        for (Permission permission : permissions) {
            String url = permission.getUrl();
            String sn = permission.getSn();
            mp.put(url,"aisellPerm["+sn+"]");


        }
        mp.put("/**","authc");
        return mp;


    }
}

二,菜单读取

menu

@Entity
@Table(name = "menu")
public class Menu extends BaseDomain{
    private String name;
    private String url;
    private String icon;

    //懒加载
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    //加载json时忽略
    private Menu parent;


    //表示临时的属性
    @Transient
    private List children = new ArrayList<>();
    下面是get,set

然后配置permission

 //加载方式懒加载
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "menu_id")
    private Menu menu;

MenuRepository

public interface MenuRepository extends BaseRepository{

    @Query("select m from Employee e join e.roles er join er.permissions p join p.menu m where e.id = ?1 ")
    public List findMenuByLoginUser(Long userid);
}

MenuService
思路就是,判断每个不同用户下面有没有父菜单,有就添加子菜单,没有就添加父菜单

public class MenuServiceImpl extends BaseServiceImpl implements IMenuService {

    @Autowired
    private MenuRepository menuRepository;



    @Override
    public List findMenuByLoginUser(Long userid) {
        //查询所有子菜单
        List childrenList = menuRepository.findMenuByLoginUser(userid);

        //创建一个集合放父菜单
        List perentList = new ArrayList<>();
        //拿到所有菜单
        for (Menu childrenMenu : childrenList) {
            //得到父菜单
            Menu parent = childrenMenu.getParent();
            //判断时候有父菜单,没有就添加,有就添加子菜单
            if (!perentList.contains(parent)){

                perentList.add(parent);
            }
                parent.getChildren().add(childrenMenu);

        }

        return perentList;
    }
}

MenuController

 @RequestMapping("/findMenuByLoginUser")
    @ResponseBody
    public List findMenuByLoginUser(){
        Employee employee = UserContext.getUser();
        //根据登陆用户的id 查询菜单
        return  menuService.findMenuByLoginUser(employee.getId());
    }

一,配置使用poi的包

两款操作java操作办公框架
jxl: jxl早期只对excel操作,在处理excel上面有很多的优势 jxl在写入上要快一点
缺点:效率低,图片支持不完善,对格式的支持不如POI强大
poi:excel和word,ppt都可以才有 poi在读取上面要快一点
缺点:不成熟,代码不能跨平台,兼容性不是那么好



  org.apache.poi
  poi
  3.11


  org.apache.poi
  poi-ooxml
  3.11

使用poi完成九九乘法表
导出

 @Test
    public void testPoiWrite99() throws Exception{
        //创建一个工作薄
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建一个表格
        XSSFSheet sheet = workbook.createSheet("九九乘法表");
        for (int i = 1; i <=9 ; i++) {
            XSSFRow row = sheet.createRow(i-1);
            for (int j = 1; j <= i ; j++) {
                //创建一个单元格
                XSSFCell cell = row.createCell(j-1);
                cell.setCellValue(i+"*"+j+"="+(i*j));
            }

        }
        //输出
        FileOutputStream out = new FileOutputStream(
                new File("99.xlsx"));
        workbook.write(out);
        out.close();
    }

用poi导入办公文件

 @Test
    public void testPoiRead() throws Exception{
        //读取
        FileInputStream fis = new FileInputStream(
                new File("empread.xlsx"));
        //得到工作薄
        XSSFWorkbook workbook = new XSSFWorkbook(fis);
        //得到第一个表格
        XSSFSheet spreadsheet = workbook.getSheetAt(0);
        //获取表格所有的row
        Iterator  rowIterator = spreadsheet.iterator();
        int count = 0;
        //循环行
        while (rowIterator.hasNext()) {
               count++;
                //取出具体哪一个行
                XSSFRow row = (XSSFRow) rowIterator.next(); //取出两行进行抛弃
            if (count > 2) {
                //得到单元格
                Iterator cellIterator = row.cellIterator();
                while (cellIterator.hasNext()) {
                    //取出单元格
                    Cell cell = cellIterator.next();
                    //判断单元格类型
                    switch (cell.getCellType()) {
                        case Cell.CELL_TYPE_NUMERIC:
                            System.out.print(
                                    cell.getNumericCellValue() + " \t\t ");
                            break;
                        case Cell.CELL_TYPE_STRING:
                            System.out.print(
                                    cell.getStringCellValue() + " \t\t ");
                            break;
                    }
                }
                System.out.println();
            }
        }
        fis.close();
    }

二,easypoi的基本使用
基本导出

 @Test
    public void testEasyuiPoi() throws Exception{

        List list = new ArrayList<>();
        EasyEmployee easyEmployee1 = new EasyEmployee();
        easyEmployee1.setName("草拟大爷");
        easyEmployee1.setAge(30);
        easyEmployee1.setSex(false);
        easyEmployee1.setBirthday(new Date());
        easyEmployee1.setHeadImage("4.bmp");

        EasyEmployee easyEmployee2 = new EasyEmployee();
        easyEmployee2.setName("小泽玛利亚");
        easyEmployee2.setAge(20);
        easyEmployee2.setSex(false);
        easyEmployee2.setBirthday(new Date());
        easyEmployee2.setHeadImage("6.bmp");
        list.add(easyEmployee1);
        list.add(easyEmployee2);
        //导出代码
        //ExportParams 设置标题 设置表名
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("av演员","女优"),
                EasyEmployee.class, list);

        //输出效果
        FileOutputStream outputStream = new FileOutputStream(new File("employee导出.xlsx"));
        workbook.write(outputStream);
        outputStream.close();
    }

测试关联对象,只导入部门和部门下面的东西

//关联对象 --表示这个对象里面也有导出的字段 深入导出
    @ExcelEntity
    private EasyDept easyDept;

测试代码

 @Test
    public void testEasyuiPoi2() throws Exception{

        List list = new ArrayList<>();

        EasyDept easyDept1 = new EasyDept();
        easyDept1.setName("无痛人流部");
        EasyDept easyDept2 = new EasyDept();
        easyDept2.setName("包皮包茎部");

        list.add(easyDept1);
        list.add(easyDept2);

        //导出代码
        //ExportParams 设置标题 设置表名
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("部门信息","部门"), EasyDept.class, list);

        //输出效果
        FileOutputStream outputStream = new FileOutputStream(new File("employee导出1.xlsx"));
        workbook.write(outputStream);
        outputStream.close();
    }

解决图像问题

 //2表示选择图片导出 1表示的文本
    @Excel(name="头像",type = 2 ,width = 40 , height = 20)

测试代码

 @Test
    public void testEasyuiPoi1() throws Exception{

        List list = new ArrayList<>();
        EasyEmployee easyEmployee1 = new EasyEmployee();
        easyEmployee1.setName("草拟大爷");
        easyEmployee1.setAge(30);
        easyEmployee1.setSex(false);
        easyEmployee1.setBirthday(new Date());
        easyEmployee1.setHeadImage("4.bmp");
        EasyDept dept1 = new EasyDept();
        dept1.setName("男优部");

        easyEmployee1.setEasyDept(dept1);
        EasyEmployee easyEmployee2 = new EasyEmployee();
        easyEmployee2.setName("小泽玛利亚");
        easyEmployee2.setAge(20);
        easyEmployee2.setSex(false);
        easyEmployee2.setBirthday(new Date());
        easyEmployee2.setHeadImage("6.bmp");

        EasyDept dept2 = new EasyDept();
        dept2.setName("女优部");

        easyEmployee2.setEasyDept(dept2);

        list.add(easyEmployee1);
        list.add(easyEmployee2);
        //导出代码
        //ExportParams 设置标题 设置表名
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("av演员","女优"),
                EasyEmployee.class, list);

        //输出效果
        FileOutputStream outputStream = new FileOutputStream(new File("employee导出.xlsx"));
        workbook.write(outputStream);
        outputStream.close();
    }

三,和springmvc集成关联

首先配置Controller
测试代码(没有开启验证)

@Controller
@RequestMapping("/import")
public class ImportController {

    //自定义验证类
    @Autowired
    private AisellEmployeeVerifyHander aisellEmployeeVerifyHander;

    @Autowired
    private IDepartmentService departmentService;

    @Autowired
    private IEmployeeService employeeService;

    @RequestMapping("/index")
    public String importPage(){

        return "import";
    }

    //导入功能 --没有验证功能
    @RequestMapping("/employeeXlsx1")
    public String employeeXlsx1(MultipartFile empFile) throws Exception {
        //这个文件怎么
        ImportParams params = new ImportParams();
        params.setTitleRows(1);

        //导入
        List list = ExcelImportUtil.importExcel(empFile.getInputStream(),
                Employee.class, params);

        for (Employee employee : list) {
            System.out.println(employee);
            //根据部门名称查询的部门对象
            String deptName = employee.getDepartment().getName();
            Department department = departmentService.findDepartmentByName(deptName);
            //设置部门
            employee.setDepartment(department);
            employee.setPassword("123456");
            employeeService.save(employee);
        }
        return "import";
    }

开启验证

 //具备验证功能
    @RequestMapping("/employeeXlsx")
    public String employeeXlsx(MultipartFile empFile, HttpServletResponse response) throws Exception {
        //这个文件怎么
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        //开启验证
        params.setNeedVerfiy(true);
        //开启自定义验证
        params.setVerifyHandler(aisellEmployeeVerifyHander);
        //导入
        ExcelImportResult result = ExcelImportUtil.importExcelMore(empFile.getInputStream(),
                Employee.class, params);
        //正确数据
        for (Employee employee : result.getList()) {
            System.out.println(employee);
            //根据部门名称查询的部门对象
            String deptName = employee.getDepartment().getName();
            Department department = departmentService.findDepartmentByName(deptName);
            //设置部门
            employee.setDepartment(department);
            employee.setPassword("123456");

            employeeService.save(employee);
        }

        //错误的数据
        for (Employee employee : result.getFailList()) {
            System.out.println("错误数据:"+employee);
        }
        //传回前台 让用户查看 修改
        if(result.isVerfiyFail()){
            //有时候信息
            Workbook failWorkbook = result.getFailWorkbook();
            //输出设置一堆参数
            //把这个文件导出
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //mime类型
            response.setHeader("Content-disposition", "attachment;filename=error.xlsx");
            response.setHeader("Pragma", "No-cache");//设置不要缓存
           //输出内容
            OutputStream ouputStream = response.getOutputStream();
            failWorkbook.write(ouputStream);
            ouputStream.flush();
            ouputStream.close();

        }
        return "import";
    }

最后自定义验证

public class AisellEmployeeVerifyHander implements IExcelVerifyHandler {

    @Autowired
    private IEmployeeService employeeService;
    @Override
    public ExcelVerifyHandlerResult verifyHandler(Employee employee) {
        ExcelVerifyHandlerResult result = new ExcelVerifyHandlerResult(true);
        boolean flag = employeeService.checkUsername(employee.getUsername());
        if(!flag){
            result.setSuccess(false);
            result.setMsg("用户名重复");
        }

        return result;
    }
}

一,系统数据字典

SystemDictionaryType

@Entity
@Table(name = "systemdictionarydetail")
public class Systemdictionarydetail extends BaseDomain{

    //定义两个常量
    public static final String PRODUCT_BRAND = "productBrand";
    public static final String PRODUCT_UNIT = "productUnit";
    private String name;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "types_id")
    private Systemdictionarytype types;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Systemdictionarytype getTypes() {
        return types;
    }

    public void setTypes(Systemdictionarytype types) {
        this.types = types;
    }
}

query

public class SystemdictionarydetailQuery extends BaseQuery{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Specification createSpecification() {
        Specification spe = Specifications.and().
                like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
                .build();

        return spe;
    }
}

Repository

public interface SystemdictionarydetailRepository extends BaseRepository{

    @Query("select d from Systemdictionarydetail d join d.types t where t.sn=?1")
    List findDetailsBySn(String sn);
}

service

public interface ISystemdictionarydetailService extends IBaseService {

    /**
     * 根据编号查询对应的数据字典明细
     * @param sn   数据字典类型的编号
     * @return
     */
    List findDetailsBySn(String sn);
}
@Service
public class SystemdictionarydetailServiceImpl extends BaseServiceImpl implements ISystemdictionarydetailService {

    @Autowired
    private SystemdictionarydetailRepository systemdictionarydetailRepository;

    @Override
    public List findDetailsBySn(String sn) {
        return systemdictionarydetailRepository.findDetailsBySn(sn);
    }
}

Controller

@Controller
@RequestMapping("/systemdictionarydetail")
public class SystemdictionarydetailController {
    @Autowired
    private ISystemdictionarydetailService systemdictionarydetailService;
    @RequestMapping("/index")
    public String index(){
        return "systemdictionarydetail/systemdictionarydetail";
    }

    //写一个方法查询数据 返回json --查数据库 findPage
    @RequestMapping("/page")
    @ResponseBody
    public UiPage page(SystemdictionarydetailQuery systemdictionarydetailQuery){
        //List systemdictionarydetails = systemdictionarydetailService.findAll();
        Page page = systemdictionarydetailService.findPageByQuery(systemdictionarydetailQuery);
        UiPage uipage = new UiPage(page);
        return uipage;
    }

    //方法 delete
    @RequestMapping("/delete")
    @ResponseBody
    public Map delete(Long id){
        Map mp = new HashMap();
        try {
            systemdictionarydetailService.delete(id);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }

    //保存方法-- 修改和新增保存
    @RequestMapping("/save")
    @ResponseBody
    public Map save(Systemdictionarydetail systemdictionarydetail){
        Map mp = new HashMap();
        try {
            systemdictionarydetailService.save(systemdictionarydetail);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }

    @RequestMapping("/update")
    @ResponseBody
    public Map update(@ModelAttribute("editSystemdictionarydetail") Systemdictionarydetail systemdictionarydetail){
        Map mp = new HashMap();
        try {
            //Systemdictionarydetail systemdictionarydetail = findOne(systemdictionarydetail.getId())
            systemdictionarydetailService.save(systemdictionarydetail);
            mp.put("success", true);
        } catch (Exception e) {
            e.printStackTrace();
            mp.put("success", false);
            mp.put("msg", e.getMessage());
        }
        return mp;

    }



    //删除方法
    @ModelAttribute("editSystemdictionarydetail")
    public Systemdictionarydetail beforeEdit(Long id, String cmd){
        Systemdictionarydetail systemdictionarydetail = null;
        if("update".equals(cmd) && id != null && !"".equals(id) ){
            systemdictionarydetail = systemdictionarydetailService.findOne(id);

        }
        return systemdictionarydetail;
    }
}

二,自主完成CRUD

使用代码生成器完成:
domain
query
repository
service
controller
还有前台页面

产品页面展示

名称 颜色 图片 成本价 销售价 类型 单位 品牌

处理大图展示方法
function loadSuccess(data) {
//看是否进来了
alert(进来了)
var rows = data.rows;
for(var i=0;i var result = rows[i];
. e a s y u i . t o o l t i p . i n i t ( .easyui.tooltip.init( .easyui.tooltip.init((“img[src=’”+result.smallpic+"’]"), {
position: “rigth”,
content: “


});
}
}
添加与修改页面

//注意颜色在回显的时候不用去写,,,type=color可以直接回显
名称:
颜色:
成本价:
销售价:
产品图片:

产品修改时回显

edit:function () {
    //选中了某一条数据才删除
    var row = productGrid.datagrid("getSelected");
    if(row){
        //隐藏有data-save属性的元素
        $("*[data-save]").hide();
        //禁用有data-save属性的input元素的验证功能
        $("*[data-save] input").validatebox("disableValidation");

        productForm.form("clear");//清除数据
        productDialog.dialog("center").dialog('open');
        //解决单位,品牌,类型的回显问题
        if(row.unit){
            row["unit.id"] = row.unit.id;
        }
        if(row.brand){
            row["brand.id"] = row.brand.id;
        }
        if(row.types){
            row["types.id"] = row.types.id;
        }
        //为form加载数据
        productForm.form("load",row);
    }else{
        $.messager.alert('提示信息','请选择一行再进行修改!','info');
    }
},

保存

@RequestMapping("/save")
@ResponseBody
public Map save(Product product,HttpServletRequest req){
    return saveOrUpdate(product,req);
}

最后删除(注意删除时把图片也删除了)

//删除功能
@RequestMapping("/delete")
@ResponseBody
public Map delete(Long id,HttpServletRequest req){
    Map map = new HashMap<>();
    try{
        Product product = productService.findOne(id);
        productService.delete(id);
        // 删除图片的代码,写在delete方法之后
        String webapp = req.getServletContext().getRealPath("/");
        if (id != null && StringUtils.isNotBlank(product.getPic())) {
            File deleteFile = new File(webapp, product.getPic());
            if (deleteFile.exists()) {
                deleteFile.delete();
            }
            File deleteSmallFile = new File(webapp, product.getSmallPic());
            if (deleteSmallFile.exists()) {
                deleteSmallFile.delete();
            }
        }
        map.put(SUCCESS,true);
    }catch (Exception e){
        map.put(SUCCESS,false);
        map.put("msg",e.getMessage());
        e.printStackTrace();
    }
    return map;
}

一,采购单模型设计

判断数据库联系
如果是下拉列表:一般是多对一,一对一
如果是复选框:一般是多对多,一对多
采购单组合关系
主表

@Entity
@Table(name="purchasebill")
public class Purchasebill extends BaseDomain {

    private Date vdate; // 交易时间 前台传过来
    private BigDecimal totalAmount; //订单总金额 --后台计算出来
    private BigDecimal totalNum; //订单数量 --后台计算出来
    private Date inputtime = new Date();//采购单录入时间 -- 后台生成
    private Date auditortime; //审核时间 --- 后台生成
    private Integer status = 0; //单据状态 0 表示待审核 1 表示审核 -1表作废
    //private Long supplierId;
   @ManyToOne(fetch = FetchType.LAZY,optional = false)
   @JoinColumn(name="supplier_id")
   private Supplier supplier;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="auditor_id")
    private Employee auditor;//审核人 录入可以为null

    @ManyToOne(fetch = FetchType.LAZY,optional = false)
    @JoinColumn(name="inputUser_id")
    private Employee inputUser;//录入人 不能为null 当前登陆用户

    @ManyToOne(fetch = FetchType.LAZY,optional = false)
    @JoinColumn(name="buyer_id")
    private Employee buyer;//采购员

    //明細  强级联  orphanRemoval 一方解除关系 去删除
    @OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy = "bill",
    orphanRemoval = true)
    private List items = new ArrayList<>();

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    public Date getVdate() {
        return vdate;
    }

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setVdate(Date vdate) {
        this.vdate = vdate;
    }

    public BigDecimal getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }

    public BigDecimal getTotalNum() {
        return totalNum;
    }

    public void setTotalNum(BigDecimal totalNum) {
        this.totalNum = totalNum;
    }

    public Date getInputtime() {
        return inputtime;
    }

    public void setInputtime(Date inputtime) {
        this.inputtime = inputtime;
    }

    public Date getAuditortime() {
        return auditortime;
    }

    public void setAuditortime(Date auditortime) {
        this.auditortime = auditortime;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Supplier getSupplier() {
        return supplier;
    }

    public void setSupplier(Supplier supplier) {
        this.supplier = supplier;
    }

    public Employee getAuditor() {
        return auditor;
    }

    public void setAuditor(Employee auditor) {
        this.auditor = auditor;
    }

    public Employee getInputUser() {
        return inputUser;
    }

    public void setInputUser(Employee inputUser) {
        this.inputUser = inputUser;
    }

    public Employee getBuyer() {
        return buyer;
    }

    public void setBuyer(Employee buyer) {
        this.buyer = buyer;
    }

    public List getItems() {
        return items;
    }

    public void setItems(List items) {
        this.items = items;
    }
}

采购明细表

@Entity
@Table(name="purchasebillitem")
public class Purchasebillitem extends BaseDomain {
        private BigDecimal price;//产品价格
        private BigDecimal num;//产品数量

        private BigDecimal amount;//产品小计
        private String descs; //产品描述
        // private Long productId;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name="product_id")
        private Product product;

        //订单 bill_id
       @ManyToOne(fetch = FetchType.LAZY,optional = false)
       @JoinColumn(name="bill_id")
       @JsonIgnore //返回页面 不展示出来
       private Purchasebill bill;


    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public BigDecimal getNum() {
        return num;
    }

    public void setNum(BigDecimal num) {
        this.num = num;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public String getDescs() {
        return descs;
    }

    public void setDescs(String descs) {
        this.descs = descs;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }

    public Purchasebill getBill() {
        return bill;
    }

    public void setBill(Purchasebill bill) {
        this.bill = bill;
    }
}

订单明细表展示页面

交易时间 供应商 采购员 总数量 总金额 状态

处理明细单审核状态

function formatStatus(action) {
    var data = {
        0:"
待审
", 1:"
已审
", "-1":"
作废
" }; return data[action]; }

8-17项目总结_第1张图片
高级查询,
因为只查询到集体的天数,所以只能查到一条数据,
因此我们把时间往后加一天处理,注意1.结束时间是不能成功获取查询的值.
如果是月底,时间会自动添加到下一个月

 @Override
    public Specification createSpecification() {

        Date tempDate = null;
        if(this.endDate!=null){
            tempDate =  DateUtils.addDays(this.endDate,1 );
            System.out.println(tempDate);
        }

        Specification spe = Specifications.and().
                ge(this.beginDate != null, "vdate",this.beginDate ).
                lt(this.endDate!=null,"vdate",tempDate).
                eq(this.status!=null && !"".equals(this.status),"status",this.status)
                .build();

        return spe;
    }

弹出采购对话框
加载采购员 和 供应商


                供应商:
                
            
            
                采购员:
                
            

二,采购单明细表格处理(难点)

表单样式可以从网上下载,也可以应课件准备好的

交易时间:
供应商:
采购员:

明细单保存
准备额外参数

 //保存方法 --提交表单的数据到后台
            purchasebillForm.form('submit', {
                    url:url,
                    onSubmit: function(param){
                        //提交 封装 items
                        //得到明细表格所有的数据 price num descs
                        var rows = $("#gridItem").datagrid('getRows');
                        for(var i=0;i

解决修改回显问题
准备一个临时副本存放数据,
用的时候才拿出来,这样就不会出现明明没有删除操作,数据却显示不出来的问题

 edit:function(){
            //选择一条数据进行修改
            var row = purchasebillGrid.datagrid('getSelected');
            if(row){
                //弹出对话框
                purchasebillDialog.dialog('center').dialog('open');
               //供货商
                if(row.supplier){
                    row["supplier.id"] = row.supplier.id;
                }
                //供货商
                if(row.buyer){
                    row["buyer.id"] = row.buyer.id;
                }
                for(var i=0;i

最后解决n to n问题
设置关联对象为null,在每次用之前清理一次
就不会出现n-to-n问题了

purchasebill.setBuyer(null);
purchasebill.setSupplier(null);
purchasebill.getItems().clear();

一,采购单报表页面查询

datagrid
页面效果展示js

$(function(){
    $('#purchasebillitemDatagrid').datagrid({
        width:500,
        height:250,
        fit:true,
        rownumbers:true,
        remoteSort:false,
        nowrap:false,
        fitColumns:true,
        toolbar:'#tb',
        url:'/purchasebillitem/findAllItemVo',
        columns:[[
            {field:'id',title:'编号',width:100,sortable:true},
            {field:'supplier',title:'供应商名称',width:80,align:'right',sortable:true},
            {field:'buyer',title:'采购员名称',width:80,align:'right',sortable:true},
            {field:'product',title:'产品名称',width:150,sortable:true},
            {field:'productType',title:'产品分类',width:60,align:'center'},
            {field:'vdate',title:'交易时间',width:180,align:'right',sortable:true},
            {field:'num',title:'数量',width:50,sortable:true},
            {field:'price',title:'价格',width:60,align:'center'},
            {field:'amount',title:'小计',width:60,align:'center'},
            {field:'status',title:'状态',width:60,align:'center',formatter:statusFormatter}
        ]],
        groupField:'groupField',
        view: groupview,
        groupFormatter:function(value, rows){
            var totalNum =0;
            var totalAmount = 0;
            //rows表示当前分组下面的行
            for(var i=0;i共"+totalNum+"件商品" +"总金额:"+totalAmount+"";
        }
    });
});

后台数据
定义一个PurchaseBillItemVo 类
用来处理分组问题, 还有date时间问题,
用构造方法创建对象,并赋值

public class PurchasebillitemVo {

    private Long id; //编号
    private String supplier; //供应商名称
    private String buyer; //采购员名称
    private String product; //产品名称
    private String productType; //产品分类
    private Date vdate; //交易时间
    private BigDecimal num; //采购数量
    private BigDecimal price; //价格
    private BigDecimal amount; //小计 = 价格*数量
    private Integer status;

    private String groupField = ""; //分组字段

    //构造方法 创建对象或者赋值
    public PurchasebillitemVo(Purchasebillitem item){
        this.id = item.getId();
        this.supplier = item.getBill().getSupplier().getName();
        this.buyer = item.getBill().getBuyer().getUsername();
        this.product = item.getProduct().getName();
        this.productType = item.getProduct().getTypes().getName();
        this.vdate = item.getBill().getVdate();
        this.num = item.getNum();
        this.price = item.getPrice();
        this.amount = item.getAmount();
        this.status = item.getBill().getStatus();
    }

    public PurchasebillitemVo(Purchasebillitem item,String groupBy){
        this.id = item.getId();
        this.supplier = item.getBill().getSupplier().getName();
        this.buyer = item.getBill().getBuyer().getUsername();
        this.product = item.getProduct().getName();
        this.productType = item.getProduct().getTypes().getName();
        this.vdate = item.getBill().getVdate();
        this.num = item.getNum();
        this.price = item.getPrice();
        this.amount = item.getAmount();
        this.status = item.getBill().getStatus();
        //根据传入的条件 进行分组
        if("o.bill.supplier.name".equals(groupBy)){
            this.groupField = this.supplier;
        }else if("o.bill.buyer.username".equals(groupBy)){
            this.groupField = this.buyer;
        }else if("MONTH(o.bill.vdate)".equals(groupBy)){
            //this.groupField = this.vdate; 7 8
            this.groupField = (DateUtils.toCalendar(this.vdate).get(Calendar.MONTH)+1)+"月";
        }else{
            this.groupField = this.supplier;
        }
    }

    public static void main(String[] args) {
        System.out.println(DateUtils.toCalendar(new Date()).get(Calendar.MONTH)+1);
    }

    public  PurchasebillitemVo(){}



    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getSupplier() {
        return supplier;
    }

    public void setSupplier(String supplier) {
        this.supplier = supplier;
    }

    public String getBuyer() {
        return buyer;
    }

    public void setBuyer(String buyer) {
        this.buyer = buyer;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public String getProductType() {
        return productType;
    }

    public void setProductType(String productType) {
        this.productType = productType;
    }

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    public Date getVdate() {
        return vdate;
    }

    public void setVdate(Date vdate) {
        this.vdate = vdate;
    }

    public BigDecimal getNum() {
        return num;
    }

    public void setNum(BigDecimal num) {
        this.num = num;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getGroupField() {
        //设置分组字段 默认按照供应商分组
       // this.groupField = this.supplier;
        return groupField;
    }

    public void setGroupField(String groupField) {
        this.groupField = groupField;
    }
}

根据前台传来的日期,状态,和用户名来查询query

public class PurchasebillitemQuery extends BaseQuery{


    private String name;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //接收时间和状态

    private Date beginDate;

    private Date endDate;

    private Integer status;

    //介绍分组字段
    private String groupBy = "o.bill.supplier.name";

    public String getGroupBy() {
        return groupBy;
    }

    public void setGroupBy(String groupBy) {
        this.groupBy = groupBy;
    }

    public Date getBeginDate() {
        return beginDate;
    }

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    //抽取查询
    @Override
    public Specification createSpecification() {
        Date tempDate = null;
        if(this.endDate!=null){
            tempDate =  DateUtils.addDays(this.endDate,1 );
            System.out.println(tempDate);
        }
        //查询 Purchasebillitem select o from purchasebillitem o where o.bill.vdate = 1? and  o.bill.status
        Specification spe = Specifications.and().
                ge(this.beginDate != null, "bill.vdate",this.beginDate ).
                lt(this.endDate!=null,"bill.vdate",tempDate).
                eq(this.status!=null && !"".equals(this.status),"bill.status",this.status)
                .build();

        return spe;
    }

service层处理

 @Autowired
    private PurchasebillitemRepository purchasebillitemRepository;

    @Override
    public List findItems(PurchasebillitemQuery itemQuery) {
        //查询所有的采购的明细
        List items = purchasebillitemRepository.findByQuery(itemQuery);
        List itemsVoList = new ArrayList<>();
        for (Purchasebillitem item : items) {
            PurchasebillitemVo itemVo = new PurchasebillitemVo(item,itemQuery.getGroupBy());
            itemsVoList.add(itemVo);
        }
        return itemsVoList;
    }

controller层处理
这里需要注意的是分组报表查询,因为前台页面效果是这样的
所以需要把查询出来的List放入map里去
8-17项目总结_第2张图片

 //分组报表查询
   
    @RequestMapping("/findAllItemVo")
    @ResponseBody
    public Map findPurchaseBillItemVo(PurchasebillitemQuery billitemQuery){

        Map mp = new HashMap();
        List items = purchasebillitemService.findItems(billitemQuery);
        mp.put("total", items.size());
        mp.put("rows", items);

        return mp;
    }

前台数据完成
引入js


js

$(function(){
    $('#purchasebillitemDatagrid').datagrid({
        width:500,
        height:250,
        fit:true,
        rownumbers:true,
        remoteSort:false,
        nowrap:false,
        fitColumns:true,
        toolbar:'#tb',
        url:'/purchasebillitem/findAllItemVo',
        columns:[[
            {field:'id',title:'编号',width:100,sortable:true},
            {field:'supplier',title:'供应商名称',width:80,align:'right',sortable:true},
            {field:'buyer',title:'采购员名称',width:80,align:'right',sortable:true},
            {field:'product',title:'产品名称',width:150,sortable:true},
            {field:'productType',title:'产品分类',width:60,align:'center'},
            {field:'vdate',title:'交易时间',width:180,align:'right',sortable:true},
            {field:'num',title:'数量',width:50,sortable:true},
            {field:'price',title:'价格',width:60,align:'center'},
            {field:'amount',title:'小计',width:60,align:'center'},
            {field:'status',title:'状态',width:60,align:'center',formatter:statusFormatter}
        ]],
        groupField:'groupField',
        view: groupview,
        groupFormatter:function(value, rows){
            var totalNum =0;
            var totalAmount = 0;
            //rows表示当前分组下面的行
            for(var i=0;i共"+totalNum+"件商品" +"总金额:"+totalAmount+"";
        }
    });
});

二,HighChart,全球使用,echart(百度开发,开源免费)

引入,HighChart
3D报表图,2D只需改变 alpha到0度就可以了

 charts3D:function(){
            //发送ajax请求到后台查询的数据吧

            var param = searchForm.serializeObject();
            $.post("/purchasebillitem/findAllGraphic",param,function(result){

                Highcharts.chart('purchasebillitemDialog', {
                    chart: {
                        type: 'pie',
                        options3d: {
                            enabled: true,
                            alpha: 45, //倾斜角度
                            beta: 0
                        }
                    },
                    title: {
                        text: '消费图'
                    },
                    tooltip: {
                        pointFormat: '{series.name}: {point.percentage:.1f}%'
                    },
                    plotOptions: {
                        pie: {
                            allowPointSelect: true,
                            cursor: 'pointer',
                            depth: 35,//深度
                            dataLabels: {
                                enabled: true,
                                format: '{point.name}'
                            }
                        }
                    },
                    series: [{
                        type: 'pie',
                        name: '消费比例',
                        data:result
                    }]
                });
            })
		    //3D图表 --打开对话框
            purchasebillitemDialog.dialog('center').dialog('open');

通过文档看到其展示数据的类型是[{},{},{}]这样,所以我们需要相应的查询语句
拼接sql语句

 //定义一个容器
  List params = new ArrayList<>();
  
    public String getWhereSql(){

        String sql = "";

        if(beginDate != null && !"".equals(beginDate)){
            sql += " and b.vdate >= ?";
            params.add(beginDate);
        }

        if(endDate != null && !"".equals(endDate)){
            sql += " and b.vdate < ?";
            params.add(endDate);
        }

        if(status != null && !"".equals(status)){
            sql += " and b.status = ?";
            params.add(status);
        }

        return sql.replace("and", "where");

    }

    public List getParams() {
        return params;
    }

    public void setParams(List params) {
        this.params = params;
    }

查询到了图标需要的值后,在把数据弄成我们想要的样子
这里要注意jpql版本不同的bug,//JPA框架的bug的
group by的语句 不要写? group by 直接就拼接sql,会导致数据的丢失,
查询不出来

 //根据jpql语句查询的数据
    @Override
    public List findItemsByJql(PurchasebillitemQuery itemQuery) {
		  List mpList = new ArrayList<>();
        String groupBy = itemQuery.getGroupBy(); 
        //根据jpql语句查询 
        String jpql = "select "+groupBy+",sum(b.totalAmount) from Purchasebillitem o join o.bill b "+itemQuery.getWhereSql()+"  group by "+groupBy;
        //查询出来的list list->数组 list.toArray()
        List list = purchasebillitemRepository.findByJpql(jpql,itemQuery.getParams().toArray());
		 String jpql1 = "select o.bill.supplier.name,sum(b.totalAmount) from Purchasebillitem o join o.bill b group by ?";

        List list1 = purchasebillitemRepository.findByJpql(jpql1,groupBy);
        System.out.println("list1:"+list1);

        for (Object[] objects : list) {
            Object name = objects[0];
            BigDecimal y = (BigDecimal)objects[1];
            Map mp = new HashMap();
            mp.put("name", name);
            mp.put("y", y);
            mpList.add(mp);
        }
        return mpList;
    }

最后controlller层处理

 //查询图形报表
    @RequestMapping("/findAllGraphic")
    @ResponseBody
    public List findAllGraphic(PurchasebillitemQuery billitemQuery){

        List itemsListMap = purchasebillitemService.findItemsByJql(billitemQuery);

        return itemsListMap;
    }

一,整个项目的基本流程

基础数据模块:,产品类型,供应商(采购),客户(销售)
权限管理 产品 数据字典 员工 部门–shiro(身份认证和授权)

采购模块
8-17项目总结_第3张图片
请购单录入 
采购请购是指企业内部向采购部门提出采购申请,或采购部门汇总企业内部采购需求提出采购清单。 
在采购管理模块——请购——请购单中,点击增加,出现空白单据 
在单据中录入请购部门、请购人员、存货编码、数量等,确认无误后保存单据; 2、请购单审核 
打开请购单列表弹出查询条件选择,录入过滤条件点击确定
程序将符合条件的单据过滤出来然后选择要审核的单据进行审核

库存模块
入库数据: 保存(stockincomebill/stockincomebillitem)
出库数据:
入库审核:
审核完之后, 进入productstock(即时库存表)和 depot(仓库表) 同时 (stockincomebill)入库单据状态变成已审核
出库审核之后:
审核完之后, 进入productstock和 depot 同时 (stockincomebill)入库单据状态变成已审核
盘点模块:(提了需求 crud)
清点模块 – 清点单(每个月有那么一两天清点)
盘盈盘亏数据 --单据
清点完之后–还有同步数据
及时库存表:(账面库存)
同一个仓库里面的产品是唯一
合并原则:(入库 通过同一个产品 同一个仓库) – 价格(加权平均法)
数量*价格 +库存数量 *价格 /数量+库存数量
保存入库–和采购单保存一样的
审核入库单(重点)审核流程:
单据变成已审核 ,改变状态 添加审核人 审核时间
更新即时库存表
更新仓库表
所以我们需要配置三张表课件上有拷过来直接改

@Entity
@Table(name="stockincomebill")
public class Stockincomebill extends BaseDomain {


    private Date vdate;// 交易时间
    private BigDecimal totalAmount;//总金额
    private BigDecimal totalNum;//总数量
    private Date inputTime = new Date();//入库事件
    private Date auditorTime;//审核时间
  
    private Integer status = 0;
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "supplier_id")
    private Supplier supplier;// 多对一,非空
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "auditor_id")
    private Employee auditor;// 审核人 多对一,可以为空
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "inputUser_id")
    private Employee inputUser;// 入库人员 多对一,非空
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "keeper_id")
    private Employee keeper;// 多对一,非空 //仓管员
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "depot_id")
    private Depot depot;// 多对一,非空
    // 一般组合关系使用List
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
    private List items = new ArrayList();
@Entity
@Table(name = "stockincomebillitem")
public class Stockincomebillitem extends BaseDomain {
    private BigDecimal price;
    private BigDecimal num;
    private BigDecimal amount;
    private String descs;
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "product_id")
    private Product product;// 多对一,非空
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "bill_id")
    private Stockincomebill bill;// 组合关系,非空

仓库

@Entity
@Table(name="depot")
public class Depot extends BaseDomain {

    private String name;
    private BigDecimal maxcapacity;
    private BigDecimal currentcapacity;
    private BigDecimal totalamount;

    public Depot(long deptid) {
        this.id = deptid;
    }

    public Depot(){}

保存操作,配置了强级联
测试下

 @Test
    public void save() throws Exception {
        //创建入库主单
        Stockincomebill bill = new Stockincomebill();

        bill.setDepot(new Depot(1L));
        //入库人员 登陆人员 入库 (仓库管理人员 --登陆人员)
        bill.setInputUser(new Employee(1L));
        //入库人员 登陆人员 入库 (仓库管理人员)
        bill.setKeeper(new Employee(2L));
        //供货商
        bill.setSupplier(new Supplier(2L));
        //交易时间(入库事件)  --  在表里面添加字段 入库时间
        bill.setVdate(new Date());
		 List items = new ArrayList();
        Stockincomebillitem billItem = new Stockincomebillitem();
        billItem.setDescs("备注1");
        billItem.setNum(new BigDecimal(1));
        billItem.setPrice(new BigDecimal(1));
        billItem.setProduct(new Product(1L));
        items.add(billItem);

        Stockincomebillitem billItem2 = new Stockincomebillitem();
        billItem2.setDescs("备注2");
        billItem2.setNum(new BigDecimal(2));
        billItem2.setPrice(new BigDecimal(2));
        billItem2.setProduct(new Product(2L));
        items.add(billItem2);

        BigDecimal totalAmount = new BigDecimal(0);// 总金额
        BigDecimal totalNum = new BigDecimal(0);// 总数量
        for (Stockincomebillitem item : items) {
            // 设置多方到一方的关系 --双向关系 级联保存
            item.setBill(bill);
            // 计算小计 price*num
            item.setAmount(item.getPrice().multiply(item.getNum()));
            // 累加
            totalAmount = totalAmount.add(item.getAmount());
            totalNum = totalNum.add(item.getNum());
        }
        // 设置总金额,总数量
        bill.setTotalAmount(totalAmount);
        bill.setTotalNum(totalNum);

        // 设置一方到多方的关系
        bill.setItems(items);

        // 级联保存
        stockincomebillService.save(bill);

接下来是审核操作

@Transactional
    public void auditStockincomebill(Long billid, Employee auditor){

        //需要审核单据
        Stockincomebill bill = stockincomebillRepository.findOne(billid);
        if(bill == null){
            throw new RuntimeException("该单据不存在");
        }
        //0表示 待审 1 表示已审 -1表示作废
        if(bill.getStatus() == 1){
            throw new RuntimeException("该单据已审核");
        }

        if(bill.getStatus() == -1){
            throw new RuntimeException("该单据已作废");
        }

        //单据里面 里面审核的时间 审核人 状态
        bill.setAuditorTime(new Date());
        bill.setAuditor(auditor);
        bill.setStatus(1);

        //保存数据 更新数据
        stockincomebillRepository.save(bill);

        //  (2)仓库变化
        Depot depot = bill.getDepot();
        //当前容量
        depot.setCurrentcapacity(depot.getCurrentcapacity().add(bill.getTotalNum()));
        depot.setTotalamount(depot.getTotalamount().add(bill.getTotalAmount()));

        //保存仓库
        depotRepository.save(depot);

        //(3)及时库存表变化 同一个仓库 同一个产品合并
        // 第一次入及时库存  直接新增 如果不是第一次 需要进行合并
        List items = bill.getItems();
        //查询当前这个产品在即时库存表离是否存在
        String jpql = "select o from Productstock o where o.product=? and o.depot=?";
        for (Stockincomebillitem item : items) {
            Product product = item.getProduct();

            List productStockList = productstockRepository.findByJpql(jpql, product, depot);
            BigDecimal totalNum = new BigDecimal("0");
            BigDecimal totalAmount = new BigDecimal("0");

            if(productStockList.size() == 0){
                //第一次  直接新增
                Productstock productStock = new Productstock();
                productStock.setDepot(depot);//仓库
                productStock.setNum(item.getNum());
                productStock.setPrice(item.getPrice());
                productStock.setAmount(item.getAmount());
                productStock.setIncomedate(new Date());//入即时库存时间
                productStock.setProduct(product);//产品
                productstockRepository.save(productStock);

            }else if(productStockList.size() == 1){
                //合并
                Productstock productstock = (Productstock)productStockList.get(0);

                totalNum =  productstock.getNum().add(item.getNum());
                totalAmount = productstock.getAmount().add(item.getAmount());
                //总数量
                productstock.setNum(productstock.getNum().add(item.getNum()));
                //总金额
                productstock.setAmount(productstock.getAmount().add(item.getAmount()));
                //加权平均价格 --四舍五入
                productstock.setPrice(totalAmount.divide(totalNum,2,BigDecimal.ROUND_HALF_EVEN));

               productstockRepository.save(productstock);
         }else{
                throw new RuntimeException("仓库出问题");
            }

        }

测试审核

 //测试审核
    @Test
    public void testAuditor() throws Exception{
        stockincomebillService.auditStockincomebill(1L, new Employee(1));
    }

二,库存预警和发送邮件

Java自带的timer不好做复杂的预警,所以
我们用了一个框架叫Qz

导包,配置文件


	org.springframework
	spring-context-support
	${org.springframework.version}


	quartz
	quartz
	1.5.2

引入配置交给spring管理





    
    
    
    

    
        
        
    

简单邮件,复杂邮件
引入配置,交给spring管理




    
        
        
        
        
        
        
        
        
            
                
                true
                
                true
            
        
    


测试

public class MailTest extends BaseTest {
   //注入一个对象
  /* @Autowired
   JavaMailSender mailSender;

   //简单发送邮件
   @Test
   public void testName() throws Exception {
   //JavaMailSenderImpl xxx = (JavaMailSenderImpl)mailSender
      // 简单邮件对象
      SimpleMailMessage msg = new SimpleMailMessage();
      // 发送人:和配置一致
      msg.setFrom("[email protected]");
      // 收件人
      msg.setTo("[email protected]");
      //抄送其他人
    
      String[] strs =  new String[]{"[email protected]","[email protected]","[email protected]","[email protected]"};
      msg.setCc(strs);

      // 主题
      msg.setSubject("好热哦");
      // 内容
      msg.setText("好想去 游泳");
      // 设置固定回邮地址
      //msg.setReplyTo("[email protected]");
      // 发送
      mailSender.send(msg);
   }

   *//**
    * 发送复杂邮件
    *//*
   @Test
   public void testSendMsg2() throws MessagingException {
      //创建复杂的邮件发送
      MimeMessage mimeMessage = mailSender.createMimeMessage();

      //复杂邮件的工具类 设置编码格式
      MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"UTF-8");

      helper.setFrom("[email protected]");

      helper.setTo("[email protected]");

      helper.setSubject("热热热热热");
      helper.setText("

这是主题

",true); //发送附件 helper.addAttachment("热成狗.jpg",new File("E:/b3317f52.bmp")); mailSender.send(mimeMessage); }*/ }

你可能感兴趣的:(8-17项目总结)