一,什么是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
@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());
}
抽取一个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;
}
}
后台
@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');
}
}
});
}
}
})
模板技术怎样输出数据
数据+模板(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();
}
}
}
支持的数据库类型
因为是基于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};
}
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());
}
}
@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();//退出
}
配置导包
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
/*
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使用代码生成器完成
权限完善
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
permission管理
<%@include file="/WEB-INF/views/head.jsp" %>
权限名称
资源路径
描述
权限编号
<%-- 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
然后配置permission
//加载方式懒加载
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "menu_id")
private Menu menu;
MenuRepository
public interface MenuRepository extends BaseRepository
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());
}
两款操作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();
}
首先配置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;
}
}
使用代码生成器完成:
domain
query
repository
service
controller
还有前台页面
产品页面展示
名称
颜色
图片
成本价
销售价
类型
单位
品牌
处理大图展示方法 产品修改时回显 保存 最后删除(注意删除时把图片也删除了) 判断数据库联系 采购明细表 订单明细表展示页面 处理明细单审核状态 弹出采购对话框 表单样式可以从网上下载,也可以应课件准备好的 明细单保存 解决修改回显问题 最后解决n to n问题 datagrid 后台数据 根据前台传来的日期,状态,和用户名来查询query service层处理 controller层处理 前台数据完成 js 引入,HighChart 通过文档看到其展示数据的类型是[{},{},{}]这样,所以我们需要相应的查询语句 查询到了图标需要的值后,在把数据弄成我们想要的样子 最后controlller层处理 基础数据模块:,产品类型,供应商(采购),客户(销售) 采购模块 库存模块 仓库 保存操作,配置了强级联 接下来是审核操作 测试审核 Java自带的timer不好做复杂的预警,所以 引入配置交给spring管理 简单邮件,复杂邮件 测试
function loadSuccess(data) {
//看是否进来了
alert(进来了)
var rows = data.rows;
for(var i=0;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: “
});
}
}
添加与修改页面
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
//删除功能
@RequestMapping("/delete")
@ResponseBody
public 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
@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.结束时间是不能成功获取查询的值.
如果是月底,时间会自动添加到下一个月 @Override
public Specification createSpecification() {
Date tempDate = null;
if(this.endDate!=null){
tempDate = DateUtils.addDays(this.endDate,1 );
System.out.println(tempDate);
}
Specification
加载采购员 和 供应商
供应商:
采购员:
二,采购单明细表格处理(难点)
准备额外参数 //保存方法 --提交表单的数据到后台
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
设置关联对象为null,在每次用之前清理一次
就不会出现n-to-n问题了purchasebill.setBuyer(null);
purchasebill.setSupplier(null);
purchasebill.getItems().clear();
一,采购单报表页面查询
页面效果展示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
定义一个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;
}
}
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
@Autowired
private PurchasebillitemRepository purchasebillitemRepository;
@Override
public List
这里需要注意的是分组报表查询,因为前台页面效果是这样的
所以需要把查询出来的List放入map里去
//分组报表查询
@RequestMapping("/findAllItemVo")
@ResponseBody
public Map findPurchaseBillItemVo(PurchasebillitemQuery billitemQuery){
Map mp = new HashMap();
List
引入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
二,HighChart,全球使用,echart(百度开发,开源免费)
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
//查询图形报表
@RequestMapping("/findAllGraphic")
@ResponseBody
public List findAllGraphic(PurchasebillitemQuery billitemQuery){
List itemsListMap = purchasebillitemService.findItemsByJql(billitemQuery);
return itemsListMap;
}
一,整个项目的基本流程
权限管理 产品 数据字典 员工 部门–shiro(身份认证和授权)
请购单录入
采购请购是指企业内部向采购部门提出采购申请,或采购部门汇总企业内部采购需求提出采购清单。
在采购管理模块——请购——请购单中,点击增加,出现空白单据
在单据中录入请购部门、请购人员、存货编码、数量等,确认无误后保存单据; 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
@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
@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
//测试审核
@Test
public void testAuditor() throws Exception{
stockincomebillService.auditStockincomebill(1L, new Employee(1));
}
二,库存预警和发送邮件
我们用了一个框架叫Qz
导包,配置文件
引入配置,交给spring管理
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);
}*/
}