1.使用到的框架
Spring +SpringMVC +SpringDataJpa+Maven+Easyui
2.使用到的技术点
一.SpringDataJpa(Spring封装了Jpa)
底层自动完成增删改查
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T> {
//根据Query拿到分页对象(分页)
Page findPageByQuery(BaseQuery baseQuery);
//根据Query拿到对应的所有数据(不分页)
List<T> findByQuery(BaseQuery baseQuery);
//根据jpql与对应的参数拿到数据
List findByJpql(String jpql,Object... values);
}
二.集成Spring +SpringMVC +SpringDataJpa
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 扫描service部分的包 purchase(进货) sale(销售) store(库存) yxb 易销宝 aisell智能销售-->
<context:component-scan base-package="cn.itsource.aisell.service" />
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置连接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--连接数据4个属性 -->
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!--maxActive: 最大连接数量 -->
<property name="maxActive" value="150" />
<!--minIdle: 最小空闲连接 -->
<property name="minIdle" value="5" />
<!--maxIdle: 最大空闲连接 -->
<property name="maxIdle" value="20" />
<!--initialSize: 初始化连接 -->
<property name="initialSize" value="30" />
<!-- 用来配置数据库断开后自动连接的 -->
<!-- 连接被泄露时是否打印 -->
<property name="logAbandoned" value="true" />
<!--removeAbandoned: 是否自动回收超时连接 -->
<property name="removeAbandoned" value="true" />
<!--removeAbandonedTimeout: 超时时间(以秒数为单位) -->
<property name="removeAbandonedTimeout" value="10" />
<!--maxWait: 超时等待时间以毫秒为单位 1000等于60秒 -->
<property name="maxWait" value="1000" />
<!-- 在空闲连接回收器线程运行期间休眠的时间值,以毫秒为单位. -->
<property name="timeBetweenEvictionRunsMillis" value="10000" />
<!-- 在每次空闲连接回收器线程(如果有)运行时检查的连接数量 -->
<property name="numTestsPerEvictionRun" value="10" />
<!-- 1000 * 60 * 30 连接在池中保持空闲而不被空闲连接回收器线程 -->
<property name="minEvictableIdleTimeMillis" value="10000" />
<property name="validationQuery" value="SELECT NOW() FROM DUAL" />
</bean>
<!-- 集成hibernate的jpa功能 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--待扫描的实体类包,不再需要persistence.xml了 -->
<property name="packagesToScan" value="cn.itsource.aisell.domain" />
<!-- 3.配置JPA的实现 -->
<!-- private JpaVendorAdapter jpaVendorAdapter; -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter -->
<!-- private boolean showSql = false;是否显示sql语句 -->
<property name="showSql" value="true" />
<!-- private boolean generateDdl = false;是否建表 -->
<property name="generateDdl" value="false" />
<!-- private String databasePlatform;原来方言 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<!-- Jpa 事务配置 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- 注解声明式事务管理 -->
<tx:annotation-driven />
<!-- Spring Data Jpa配置 ********************************************-->
<!-- base-package:扫描的包 dao层 -->
<jpa:repositories base-package="cn.itsource.aisell.repository" transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"
factory-class="cn.itsource.aisell.repository.BaseRepositoryFactoryBean"/>
<!--加载shiro的配置文件-->
<import resource="applicationContext-shiro.xml"></import>
<import resource="classpath:applicationContext-qz.xml"></import>
<import resource="classpath:applicationContext-email.xml"></import>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!-- 对静态资源进行放行 -->
<mvc:default-servlet-handler />
<!-- 扫描controller部分的包 -->
<!-- @Component组件, @Repository持久层, @Service业务逻辑层, and @Controller控制器 -->
<context:component-scan base-package="cn.itsource.aisell.web" />
<!-- 添加mvc对@RequestMapping等注解的支持 -->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json; charset=UTF-8</value>
<value>application/x-www-form-urlencoded; charset=UTF-8</value>
</list>
</property>
<!-- No serializer:配置 objectMapper 为我们自定义扩展后的 CustomMapper,解决了返回对象有关系对象的报错问题 department(额外的属性 handler) -->
<property name="objectMapper">
<bean class="cn.itsource.aisell.common.CustomMapper"></bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 扫描easypoi的一些view:视图 -->
<context:component-scan base-package="cn.afterturn.easypoi.view" />
<context:component-scan base-package="cn.itsource.aisell.common"/>
<!-- bean的视图解析器 p:order="0":顺序在最前面 -->
<bean id="beanNameViewResolver" class="org.springframework.web.servlet.view.BeanNameViewResolver"
p:order="0" />
<!-- ViewResolver 视图解析器 (struts2视图类型类似) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->
<!-- 希望跳转jsp是[/WEB-INF/views/前缀][xxx变量][.jsp后缀] -->
<!-- * @see #setPrefix -->
<property name="prefix" value="/WEB-INF/views/" />
<!-- * @see #setSuffix -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 错误:提示告诉开发者你没有配置文件上传解析器。 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize">
<value>1048576</value>
</property>
</bean>
</beans>
三.基本的CRUD(layer,jquery.form…) -> Ajax(局部刷新)
解决数据丢失问题
package cn.itsource.aisell.web.controller;
import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.itsource.aisell.domain.Employee;
import cn.itsource.aisell.query.BaseQuery;
import cn.itsource.aisell.query.EmployeeQuery;
import cn.itsource.aisell.service.IEmployeeService;
import cn.itsource.aisell.util.AjaxResult;
import cn.itsource.aisell.util.PageUi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private IEmployeeService employeeService;
@RequestMapping("/index")
public String index(){
return "employee";
}
//查询数据 /employee/page
//{total:111,rows:[{},{}]}
@RequestMapping("/page")
@ResponseBody
public PageUi<Employee> page(EmployeeQuery employeeQuery){
//查询数据 分页查询方法
// List<Employee> employees = employeeService.findAll();
Page page = employeeService.findPageByQuery(employeeQuery);
//封装返回对象 必须要 total rows
PageUi pageUi = new PageUi(page);
return pageUi;
}
//删除失败 {success:false,msg:'成功'} AjaxResult
/*@RequestMapping("/delete")
@ResponseBody
public Map delete(Long id){
Map mp = new HashMap();
try {
employeeService.delete(id);
mp.put("success", true);
mp.put("msg", "操作成功");
} catch (Exception e) {
e.printStackTrace();
mp.put("success", false);
mp.put("msg", e.getMessage());
}
return mp;
}*/
@RequestMapping("/delete")
@ResponseBody
public AjaxResult delete(Long id){
try {
employeeService.delete(id);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult("操作失败"+e.getMessage());
}
}
//写个保存方法
@RequestMapping("/save")
@ResponseBody
public AjaxResult save(Employee employee){
return saveOrUpdate(employee);
}
@RequestMapping("/update")
@ResponseBody
//把查询出来的老数据和新数据进行叠加 新数据会覆盖老数据,没有接收,就不会覆盖
public AjaxResult update(@ModelAttribute("editEmployee") Employee employee){
//修改代码
return saveOrUpdate(employee);
}
public AjaxResult saveOrUpdate(Employee employee){
try {
employeeService.save(employee);
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
return new AjaxResult("操作失败"+e.getMessage());
}
}
//每次访问controller数据的时候都要进入该方法
//修改
@ModelAttribute("editEmployee")
public Employee beforeEdit(Long id,String cmd){
System.out.println("---------------------");
if(id != null && "update".equals(cmd)){
//根据id 查询老数据 删除和修改都要id值,只需要修改进入
Employee employee = employeeService.findOne(id);
//清空关联对象 -- 记住 以后遇到n-to-n 把关联对象清空 -- 记住这句话 保永生
employee.setDepartment(null);
return employee;
}else{
return null;
}
}
//下载方法 download
@RequestMapping("/download")
//参1:前台传输的username passsword 需要高级查询不分页方法 findByQuery
//惨2:模型ModelMap
//参3:req图片保存路径
public String download(EmployeeQuery employeeQuery, ModelMap map, HttpServletRequest req){
//根据查询 查询数据
List<Employee> employees = employeeService.findByQuery(employeeQuery);
String realPath = req.getServletContext().getRealPath("");//E:\JavaEEIdeacode\aisell\src\main\web/images/head/avatar1.jpg
employees.forEach(e->{
//E:\JavaEEIdeacode\aisell\out\artifacts\aisell_Web_exploded\images\head
e.setHeadImage(realPath+e.getHeadImage());
System.out.println(e.getHeadImage());
});
//导出参数设置
//E:\JavaEEIdeacode\aisell\src\main\web\images\head\sss.jpg
ExportParams params = new ExportParams("员工数据", "员工表格1", ExcelType.XSSF);
//固定两列的意思
params.setFreezeCol(2);
map.put(NormalExcelConstants.DATA_LIST, employees); // 数据集合
map.put(NormalExcelConstants.CLASS, Employee.class);//导出实体
map.put(NormalExcelConstants.PARAMS, params);//参数
map.put(NormalExcelConstants.FILE_NAME, "xxx");//文件名称
return NormalExcelConstants.EASYPOI_EXCEL_VIEW;//View名称
}
}
四.前端验证(jquery.validate.js)
模板技术(freemarker-ftl,velocity-vm)
save:function(){
var id = $("#employeeId").val();
var url="/employee/save";
if(id){
url="/employee/update?cmd=update";
}
//保存方法
employeeForm.form('submit',{
url:url,
onSubmit: function(){
//重复密码验证 比较两个值是否相等 如果不相等 return false
//表示验证通过才能提交
return employeeForm.form("validate");
},
success:function(data){
var result = JSON.parse(data);//转成相应的json数据
if(result.success) {
employeeGrid.datagrid('reload');
}else{
$.messager.alert('提示信息','操作失败!,原因:'+result.msg,"error");
}
employeeDialog.dialog('close');
}
})
}
模板技术
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);
}
五.权限shrio(登录,菜单,访问) -> 理解
用户-角色-菜单/权限
身份验证
**
* 自定义一个Realm
*/
public class MyRealm extends AuthorizingRealm {
//获取到这个Realm的名称(随便取)
@Override
public String getName() {
return "MyRealm";
}
//进行授权的认证
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//进行登录的认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//明显的知道:这个authenticationToken就是UsernamePasswordtoken
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
String username = token.getUsername(); //拿到用户名(注:这个用户名是传过来的)
//这里根据用户名去获取密码(如果没有获取到,相当于这个用户不存在,就返回null值)
String password = getByName(username);
if(password==null){
return null;
}
//创建一个简单的身份信息(把用户名与密码放进去-注:它会自动的比较获取的密码与你传过来的密码)
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
return authenticationInfo;
}
//模拟从数据库中获取信息
private String getByName(String username) {
if("admin".equals(username)){
return "123456";
}else if("guest".equals(username)){
return "abcd";
}
return null;
}
}
授权管理
public class MyRealm extends AuthorizingRealm {
//获取到这个Realm的名称(随便取)
@Override
public String getName() {
return "MyRealm";
}
//进行授权的认证
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//拿到认证的主要信息(用户名)
String username = (String) principalCollection.getPrimaryPrincipal();
//模拟根据用户名拿到角色信息与权限信息
Set<String> roles = getRolesByUsername(username);
Set<String> permissions = getPermissionsByUsername(username);
//拿到验证信息对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//设置用户的角色
authorizationInfo.setRoles(roles);
//设置用户的权限
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
//模拟根据用户名拿到角色的功能
private Set<String> getRolesByUsername(String username) {
Set<String> roles = new HashSet<>();
roles.add("admin");
roles.add("it");
return roles;
}
//模拟根据用户名拿到权限的功能
private Set<String> getPermissionsByUsername(String username) {
Set<String> permissions = new HashSet<>();
permissions.add("employee.*");
permissions.add("department.save");
return permissions;
}
...
}
密码学(加密加盐)
@Test
public void testMyRealm() throws Exception{
//创建自己定义的Realm
MyRealm myRealm = new MyRealm();
//把Realm放到securityManager中去
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(myRealm);
//把权限管理器放到相应的环境中(我们可以在项目任何位置拿到)
SecurityUtils.setSecurityManager(securityManager);
//设置咱们Realm的密码匹配器(我们的密码要怎么处理)
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5"); //匹配器使用MD5的算法
matcher.setHashIterations(10);//加密算法要迭代多少次
myRealm.setCredentialsMatcher(matcher);
//拿到当前用户(Subject就是当前用户,游客)
Subject currentUser = SecurityUtils.getSubject();
//准备登录的令牌(准备用户名与密码) -> 这里的密码进行了加密
UsernamePasswordToken token = new UsernamePasswordToken("admin","123456");
try {
//根据令牌进行功能登录(当前用户进行登录)
currentUser.login(token);
System.out.println("登录成功啦。。。。");
} catch (UnknownAccountException e) {
System.out.println("这个账号不存在!" + token.getPrincipal());
e.printStackTrace();
} catch (IncorrectCredentialsException ice) {
System.out.println("这个密码不存在!" + token.getPrincipal());
ice.printStackTrace();
}catch (AuthenticationException e){
System.out.println("i don't k");
}
}
/**
* algorithmName:加密算法(md5,sha)
* source:原始密码
* salt,加盐
* hashIterations:遍历次数
*/
SimpleHash simpleHash = new SimpleHash("MD5","admin","itsource",10);
System.out.println(simpleHash);
会话管理
六.导入导出(上传,下载,Excel的创建与读取)
JXL:只支持Excel
POI: 支持多种办公软件
**
* 导出功能:下载
* @param map
* @return
*/
@RequestMapping("/download")
public String download(ModelMap map,EmployeeQuery query, HttpServletRequest request) {
//拿到所有数据
List<Employee> list = employeeService.findByQuery(query);
//获取到真实路径
//解决了下载的图片的路径问题
String realPath = request.getServletContext().getRealPath("");
list.forEach(e -> {
e.setHeadImage(realPath+e.getHeadImage());
System.out.println(e.getHeadImage());
});
//设置一些属性
ExportParams params = new ExportParams("员工管理", "明细", ExcelType.XSSF);
//params.setFreezeCol(3);
map.put(NormalExcelConstants.DATA_LIST, list); // 数据集合
map.put(NormalExcelConstants.CLASS, Employee.class);//导出实体
map.put(NormalExcelConstants.PARAMS, params);//参数
map.put(NormalExcelConstants.FILE_NAME, "employee");//文件名称
//返回的名称 :easypoiExcelView -> 并没有找我的bean,而且当做一个路径去进行访问
// 现在默认去找的视图解析器,而没有找我的那一个bean
return NormalExcelConstants.EASYPOI_EXCEL_VIEW;//View名称
}
@RequestMapping("/employeeXlsx")
public String employeeXlsx(MultipartFile empFile, HttpServletResponse response) throws Exception {
//准备导入的参数
ImportParams params = new ImportParams();
params.setTitleRows(1);
// need:需要 verfiy:核实,验证
params.setNeedVerfiy(true); //需要验证
//excel导入的一个结果
ExcelImportResult<Employee> result = ExcelImportUtil.importExcelMore(
empFile.getInputStream(),
Employee.class, params);
//引入正确的list(正常保存)
result.getList()[验证完后正确的数据].forEach(e ->{
// System.out.println(e+","+e.getDepartment());
//根据部门名称拿到它的部门,再放到对应的员工中
Department dept = departmentService.findByName(e.getDepartment().getName());
e.setDepartment(dept);
//给一个默认密码
e.setPassword("123");
employeeService.save(e);
});
// //引入错误的list
// result.getFailList()[验证后错误的数据].forEach(e ->{
// System.out.println("错误的:"+e);
// });
//如果有错误,就直接导出错误文件到前台
// Verfiy:检验 Fail:失败
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";
}
七.产品模块(自己练习)
增删改查
八.采购模块(组合关系的操作)
日期的查询/组合关系的配置/(前端比较麻烦)
@Entity
@Table(name = "purchasebill")
public class Purchasebill extends BaseDomain {
private Date vdate;// 交易时间 -> 需要录入(时间set的时候加上@DateTimeFormat(pattern = "yyyy-MM-dd"))
private BigDecimal totalAmount; //总金额 -> 明细计算
private BigDecimal totalNum; //总数量 -> 明细计算
private Date inputTime = new Date(); //录入时间 ->系统自动生成 当前系统时间
private Date auditorTime; //审核时间 -> 可以为空,审核时自己生成
/**
* 0待审,1已审,-1作废
*/
private Integer status = 0; //单据状态 -> 默认待审
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "supplier_id")
private Supplier supplier;// 多对一,optional非空 供应商(需要选择)
@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 = "buyer_id")
private Employee buyer;// 多对一,非空 采购员 -> 需要
// 一般组合关系使用List
/**
* 组合关系:整体和部分 不能分开 --强级联
* 一个订单有多个明细
* cascade:ALL 强级联(支持级联保存和级联删除)
* mappedBy:让一方放弃管理 ,交给多方来维护 性能要高一点
* 双向一对多或者多对一 一方放弃管理,性能要高一点
* orphanRemoval:孤儿删除 可以通过一方删除多方 让一方解除关系 通过一方去上删除
*
*/
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Purchasebillitem> items = new ArrayList<Purchasebillitem>();
@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;
}
//产品明细
@Entity
@Table(name = "purchasebillitem")
public class Purchasebillitem 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")
@JsonIgnore //生成json的时候忽略这个属性
private Purchasebill bill;// 组合关系,非空
九.报表(HighCharts)
ar itsource={
//查询数据
search:function () {
//需要先引入 jquery.serializejson.js 才可以使用这个方法
var params = searchForm.serializeJSON();
purchaseBillItemGrid.datagrid('load',params);
},
chart3D:function () {
var params = searchForm.serializeJSON();
$.post("/purchaseBillItem/findCharts",params,function (result) {
Highcharts.chart('purchaseBillItemDialog', {
chart: {
type: 'pie',
options3d: {
enabled: true,
alpha: 45,
beta: 0
}
},
title: {
text: '采购订单数据对象'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
depth: 35,
dataLabels: {
enabled: true,
format: '{point.name}'
}
}
},
series: [{
type: 'pie',
name: '比例',
data: result
}]
});
purchaseBillItemDialog.dialog("center").dialog('open');
})
},
chart2D:function () {
var params = searchForm.serializeJSON();
$.post("/purchaseBillItem/findCharts",params,function (result) {
Highcharts.chart('purchaseBillItemDialog', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: '2018年1月浏览器市场份额'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
name: '比例',
colorByPoint: true,
data: result
}]
});
purchaseBillItemDialog.dialog("center").dialog('open');
})
}
}
十.业务(定时调试,邮件发送)
定时任务
```javascript
@Service("QzJob")
public class QuartzJobServiceImpl implements IQuartzJobService {
@Autowired
private IProductstockService productstockService;
@Override
public void work() {
System.out.println(productstockService);
System.out.println("---------------------------------");
String jpql ="select o from Productstock o where o.id = ?";
List list = productstockService.findByJpql(jpql, 1L);
if(list.size() > 0 ){
System.out.println("库存不足");
}else{
System.out.println("库存很足...");
}
}
}
9.9.邮件
public class MailTest extends BaseServiceTest {
@Autowired
JavaMailSender mailSender;
@Test
public void testName() throws Exception {
//JavaMailSenderImpl xxx = (JavaMailSenderImpl)mailSender
// 简单邮件对象
SimpleMailMessage msg = new SimpleMailMessage();
// 发送人:和配置一致
msg.setFrom("zytestitsource1@126.com");
// 收件人
msg.setTo("zytestitsource@163.com");
// 主题
msg.setSubject("牛皮大学录取通知书");
// 内容
msg.setText("你已经被录取了");
// 设置固定回邮地址
//msg.setReplyTo("xxxx@xxx.com");
// 发送
mailSender.send(msg);
}
/**
* 发送复杂邮件
*/
@Test
public void testSendMsg2() throws MessagingException {
//创建复杂的邮件发送
MimeMessage mimeMessage = mailSender.createMimeMessage();
//复杂邮件的工具类
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"UTF-8");
helper.setFrom("zytestitsource1@126.com");
helper.setTo("zytestitsource@163.com");
helper.setSubject("测试一把");
helper.setText("<h1>男男女女</h1>",true);
//发送附件
helper.addAttachment("美女.jpg",new File("E:/timg.jpg"));
helper.addAttachment("java.docx",new File("E:/新建文本文档 (2).txt"));
mailSender.send(mimeMessage);
}
}
3.项目模块部分
基础模块
用户 部门 权限 角色
业务模块(核心)
采购 (进货)管理 销售管理 库存管理
基础数据模块
数据字典
4.在项目中学习到的东西
4.1 熟悉了项目整体的搭建
4.2 对项目中的执行流程思路得到了加强
前端页面 — js easyui – controller—service—repository—query–domain
4.3 项目模块中涉及到了大量的增删改查,crud能力得到了提高
4.4 对项目中的业务有了基本的认识
4.5 学习到了一些新的技术 比如shrio easypoi highcharts 定时任务 邮件发送等…