细粒度,图片上传,POI技术

本文介绍了一个系统的细粒度权限控制实现,并详细讲解了如何使用Java POI技术进行Excel文件的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今日内容

  • 项目组件完善
  • 图片上传
  • 细粒度权限控制
  • POI技术

第一章 附件管理

1. 附件列表

alt

export_manager_web模块的com.itheima.web.controller.cargo下创建ExtCproductController

package com.itheima.web.controller.cargo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.github.pagehelper.PageInfo;
import com.itheima.domain.cargo.ExtCproductExample;
import com.itheima.domain.cargo.Factory;
import com.itheima.domain.cargo.FactoryExample;
import com.itheima.service.cargo.ExtCproductService;
import com.itheima.service.cargo.FactoryService;
import com.itheima.web.controller.BaseController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
@RequestMapping("/cargo/extCproduct")
public class ExtCproductController extends BaseController {

@Reference
private ExtCproductService extCproductService;

@Reference
private FactoryService factoryService;

@RequestMapping(value = "/list", name = "附件列表查询")
public String list(
@RequestParam(defaultValue = "1", name = "page") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
String contractId, String contractProductId) {

ExtCproductExample extCproductExample = new ExtCproductExample();

//1 查询当前货物下的所有附件
extCproductExample.createCriteria().andContractProductIdEqualTo(contractProductId);
PageInfo pageInfo = extCproductService.findByPage(pageNum, pageSize, extCproductExample);
request.setAttribute("page", pageInfo);


//2 查询所有生产附件的厂家列表
FactoryExample factoryExample = new FactoryExample();
factoryExample.createCriteria().andCtypeEqualTo("附件");
List<Factory> factoryList = factoryService.findAll(factoryExample);
request.setAttribute("factoryList", factoryList);

//3. 回传合同id 和 货物id
request.setAttribute("contractId", contractId);
request.setAttribute("contractProductId", contractProductId);

return "/cargo/extc/extc-list";
}

}

2. 新增附件

2.1 ExtCproductController
@RequestMapping(value = "/edit", name = "附件新增或编辑")
public String edit(ExtCproduct extCproduct) {
if (StringUtils.isEmpty(extCproduct.getId())) {
//1. 设置主键
extCproduct.setId(UUID.randomUUID().toString());

//2. 设置企业信息
extCproduct.setCompanyId(getCompanyId());
extCproduct.setCompanyName(getCompanyName());

extCproductService.save(extCproduct);
} else {
extCproductService.update(extCproduct);
}

//重定向到list方法
return "redirect:/cargo/extCproduct/list.do?contractId=" + extCproduct.getContractId() + "&contractProductId=" + extCproduct.getContractProductId();
}
2.2 ExtCproductServiceImpl
@Override
public void save(ExtCproduct extCproduct) {
// 查询合同对象
Contract contract = contractDao.selectByPrimaryKey(extCproduct.getContractId());
// 计算小计金额
double amount = extCproduct.getCnumber() * extCproduct.getPrice();
extCproduct.setAmount(amount);

// 保存附件
extCproductDao.insertSelective(extCproduct);
// 修改合同的附件种数
contract.setExtNum(contract.getExtNum() + 1);
// 修改合同的总金额
contract.setTotalAmount(contract.getTotalAmount() + amount);
contractDao.updateByPrimaryKeySelective(contract);
}

3. 修改附件

alt
3.1 跳转修改页面

修改ExtCproductController添加代码

  @RequestMapping(value = "/toUpdate", name = "跳转附件编辑页面")
public String toUpdate(String id) {
//1. 根据id查询当前附件信息
ExtCproduct extCproduct = extCproductService.findById(id);
request.setAttribute("extCproduct", extCproduct);

//2. 查询所有生产附件的厂家列表
FactoryExample factoryExample = new FactoryExample();
factoryExample.createCriteria().andCtypeEqualTo("附件");
List<Factory> factoryList = factoryService.findAll(factoryExample);
request.setAttribute("factoryList", factoryList);

//3. 转发到修改页面
return "/cargo/extc/extc-update";
}
3.2 修改附件

修改ExtCproductServiceImpl添加代码

@Override
public void update(ExtCproduct extCproduct) {


//根据合同id,得到合同对象
Contract contract = contractDao.selectByPrimaryKey(extCproduct.getContractId());

//根据附件id查询附件的信息
ExtCproduct extCproductOld = extCproductDao.selectByPrimaryKey(extCproduct.getId());


//附件修改
//计算小计金额
Double amount = extCproduct.getPrice() * extCproduct.getCnumber();
extCproduct.setAmount(amount);

//执行修改
extCproductDao.updateByPrimaryKeySelective(extCproduct);

//合同修改
//修改总金额 - 源小计 + 新小计
contract.setTotalAmount(contract.getTotalAmount() - extCproductOld.getAmount() + amount);

// 执行合同修改
contractDao.updateByPrimaryKeySelective(contract);
}

4. 删除附件

alt
4.1 ExtCproductController
@RequestMapping(value = "/delete", name = "附件删除")
public String delete(String id, String contractId, String contractProductId) {
//调用service删除
extCproductService.delete(id);//附件id

//重定向到list方法
return "redirect:/cargo/extCproduct/list.do?contractId=" + contractId + "&contractProductId=" + contractProductId;
}
4.2 ExtCproductServiceImpl
@Override
public void delete(String id) {
//1. 根据附件id查询附件信息
ExtCproduct extCproduct = extCproductDao.selectByPrimaryKey(id);

//2. 根据合同id查询合同信息
Contract contract = contractDao.selectByPrimaryKey(extCproduct.getContractId());


//附件删除
extCproductDao.deleteByPrimaryKey(id);

//货物无影响
//合同修改
//1. 修改合同中的附件数量 - 1
contract.setExtNum(contract.getExtNum() - 1);

//2. 修改合同中的总金额 - 要删除的附件的小计
contract.setTotalAmount(contract.getTotalAmount() - extCproduct.getAmount());

//3. 执行修改
contractDao.updateByPrimaryKeySelective(contract);
}

第二章 项目中的图片上传

前端上传到后台: SpringMVC 文件上传解析器( 前端三要素 )

后台上传到七牛云: 工具类

在当前项目中的货物和附件的添加和修改页面, 都是需要做文件上传功能的, 下面就来实现以下

1. 工具类准备

alt
qiniu.accessKey=B6NvfR2Gp_**********wKsJ4ISpdsORS85ZH2Z-
qiniu.secretKey=vS5YNOikZj**********G1hZR-7i-NLRbSIL71tB
qiniu.bucket=saas-tj4
qiniu.rtValue=http://qi8eho848.hn-bkt.clouddn.com/

注意: 一定要删除dao模块中Spring配置文件中的引入外部配置的部分

alt

2. 配置文件上传解析器

export_manager_web模块下的resources下的spring/spring-mvc.xml文件中添加文件上传解析器

<!--文件上传解析器, 这个id不能随便改-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为 5MB -->
<property name="maxUploadSize" value="5242880" />
</bean>

3. 代码编写

3.1 页面代码调整

修改页面中文件上传表单的enctype=”multipart/form-data”属性

alt
3.2 后台代码编写
@Autowired
private FileUploadUtil fileUploadUtil;

@RequestMapping(value = "/edit", name = "货物新增,修改")
public String edit(ContractProduct contractProduct, MultipartFile productPhoto ) {
// 文件上传

try {
String filePath = fileUploadUtil.upload(productPhoto);
contractProduct.setProductImage(filePath);
} catch (Exception e) {
e.printStackTrace();
System.out.println("文件上传失败");
throw new RuntimeException(e);
}

if (StringUtils.isEmpty(contractProduct.getId())) {
//1. 设置主键
contractProduct.setId(UUID.randomUUID().toString());
//2. 设置企业信息
contractProduct.setCompanyId(getCompanyId());
contractProduct.setCompanyName(getCompanyName());

contractProductService.save(contractProduct);


} else {
contractProductService.update(contractProduct);
}
//重定向到list方法
return "redirect:/cargo/contractProduct/list.do?contractId=" + contractProduct.getContractId();
}

第三章 细粒度权限控制(面试)

粗粒度权限:将权限控制到类型级别 (张三可以访问部门信息 , 但是不能访问用户信息) shiro

细粒度权限:将权限控制到数据级别 (张三可以访问1号用户信息, 但是不能访问2号用户信息) 自己写SQL

一个优秀的后台程序应当做到对权限的细粒度控制, 即数据级别的权限控制

1. 需求分析

在我们的系统中,除了两类管理员之外,员工也分为三类:

  • 普通员工:只能看自己的合同数据
  • 部门经理:可以看到本部分所有员工的合同数据
  • 总经理:可以看到本部门及所有子部门的合同数据
- 4  普通员工:只能看自己的合同数据                    select * from co_contract where  create_by = 'session获取登录人的id'
- 3 部门经理:可以看到本部分所有员工的合同数据 select * from co_contract where create_dept = 'session获取登录人的所在部门的id'
- 2 总经理:可以看到本部门及所有子部门的合同数据 select * from co_contract where create_dept like 'session获取登录人的所在部门的id%'

if(degree == 4){
select * from co_contract where create_by = 'session获取登录人的id'
}else if(degree == 3){
select * from co_contract where create_dept = 'session获取登录人的所在部门的id'
}else if(degree == 2){
select * from co_contract where create_dept like 'session获取登录人的所在部门的id%'
}else{
不受细粒度权限控制
}

2. 代码实现

修改ContractController中查询合同列表的方法

@RequestMapping(value = "/list", name = "合同列表查询")
public String list(
@RequestParam(defaultValue = "1", name = "page") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {

ContractExample contractExample = new ContractExample();

//1 封装条件
ContractExample.Criteria criteria = contractExample.createCriteria();
criteria.andCompanyIdEqualTo(getCompanyId());

//判断用户等级,根据等级不同去拼接不同条件
Integer degree = getUser().getDegree();
if (degree == 4) {//普通员工
criteria.andCreateByEqualTo(getUser().getId());
} else if (degree == 3) {//部门经理
criteria.andCreateDeptEqualTo(getUser().getDeptId());
} else if (degree == 2) {//总经理
criteria.andCreateDeptLike(getUser().getDeptId() + "%");
}

//2 排序
contractExample.setOrderByClause("create_time desc");

PageInfo pageInfo = contractService.findByPage(pageNum, pageSize, contractExample);
request.setAttribute("page", pageInfo);

return "/cargo/contract/contract-list";
}

3. 测试

系统中已经内置好了几个账户用于测试,结构如下,密码都是123 ,分配的角色都是销售专责,权限是只能管理购销合同

alt

第四章 POI报表技术

1. 概述

1.1 简介

在企业内部系统中,有很多地方会用到Excel表格,目前的Excel分为两个大的版本:Excel2003和Excel2007及以上。两者之间的区别如下:

区别Excel 2003Excel 2007及以上
扩展名xlsxlsx
数据结构二进制格式xml格式
单sheet数据量行:65535、列:256行:1048576、列:16384
特点存储容量有限基于xml压缩,占用空间小,操作效率高

Java中常见的用来操作Excl的方式一般有2种:JXL和POI。

  • JXL只能对Excel进行操作,属于比较老的框架,它只支持到Excel 95-2000的版本,现在已经停止更新和维护。

  • POI是apache的项目,可对微软的Word、Excel、PPT进行操作,包括office2003和2007两个大版本,是目前主流的操作execl的技术。

1.2 Execl基础概念

Execl基础概念在POI中的API描述如下:

Execl中的概念2003版本对象2007版本对象
工作簿(WorkBook)HssfWordBookXssfWorkBook
工作表(Sheet)HssfSheetXssfSheet
行(Row)HssfRowXssfRow
单元格(Cell)HssfCellXssfCell

2. 入门案例

2.1 创建工程,引入依赖
<dependencies>
<!--2003-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.1</version>
</dependency>
<!--2007-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<!--百万级别数据-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
2.2 创建Execl
package com.itheima.poi;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/17 11:30
* @version: 1.1
*/
public class CreatePoiDemo {

public static void main(String[] args) throws IOException {
// 创建一个Execl工作簿
Workbook workbook = new XSSFWorkbook();
// 使用工作簿创建一个工作表
Sheet sheet = workbook.createSheet();
// 设置列宽
sheet.setColumnWidth(0,20*256);
// 使用工作表创建一个行,使用索引计数
Row row = sheet.createRow(0);
// 使用行创建一个单元格,使用索引计数
Cell cell = row.createCell(0);
// 写入数据
cell.setCellValue("生活就是这么简单");

// 写入文件
workbook.write(new FileOutputStream(new File("E:\\项目一\\资料\\data.xlsx")));
}
}
2.3 读取Execl
package com.itheima.poi;

import com.itheima.domain.ContractProduct;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/17 11:43
* @version: 1.1
*/
public class ReadPoiDemo2 {
public static void main(String[] args) throws IOException {
// 创建工作簿对象,并读取数据
Workbook workbook = new XSSFWorkbook(new FileInputStream(new File("E:\\项目一\\资料\\3-货物导入模板\\上传货物模板.xlsx")));
// 通过工作簿获取到工作表,通过索引获取
Sheet sheet = workbook.getSheetAt(0);
// 通过工作表获取行 获取方式是遍历获取

List<ContractProduct> list1 = new ArrayList<ContractProduct>();

for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
Object[] objects = new Object[row.getLastCellNum()];
for (int j = 1 ; j < row.getLastCellNum(); j++){
objects[j-1]=getCellValue(row.getCell(j));
}
//System.out.println(objects.toString());
list1.add(new ContractProduct(objects));
}
for (ContractProduct contractProduct : list1) {
System.out.println(contractProduct);
}

System.out.println(list1);

}

/**
* @description
* @author mryhl
* @date 2020/10/17 11:51
* @return 解析每个单元格的数据
*/
public static Object getCellValue(Cell cell) {
Object obj = null;
CellType cellType = cell.getCellType(); //获取单元格数据类型
switch (cellType) {
case STRING: {
obj = cell.getStringCellValue();//字符串
break;
}
//excel默认将日期也理解为数字
case NUMERIC: {
if (DateUtil.isCellDateFormatted(cell)) {
obj = cell.getDateCellValue();//日期
} else {
obj = cell.getNumericCellValue(); // 数字
}
break;
}
case BOOLEAN: {
obj = cell.getBooleanCellValue(); // 布尔
break;
}
default: {
break;
}
}
return obj;
}
}

第五章 货物导入

1. 需求分析

alt

2. 进入货物导入页面

alt

修改ContractProductController, 添加方法

@RequestMapping(value = "/toImport", name = "跳转货物批量上传的页面")
public String toImport(String contractId) {
//回显合同id
request.setAttribute("contractId", contractId);

//转发到上传页面
return "/cargo/product/product-import";
}

3. 实现导入功能

3.1 ContractProductController
@RequestMapping(value = "/import", name = "货物批量上传")
public String imports(String contractId, MultipartFile file) throws IOException {
//1. 接收传递过来的参数 合同id 货物的文件

//2. 读取一个File--流--工作簿
Workbook workbook = new XSSFWorkbook(file.getInputStream());

//3. 使用工作簿获取工作表
Sheet sheet = workbook.getSheetAt(0);

//4. 从工作表获取行
List<ContractProduct> list = new ArrayList<>();
for (int i = 1; i < sheet.getLastRowNum() + 1; i++) {
Row row = sheet.getRow(i);
//5 从行中获取单元格
Object[] objs = new Object[9];
for (int j = 1; j < row.getLastCellNum(); j++) {
//6. 从单元格中获取数据
Cell cell = row.getCell(j);
Object cellValue = getCellValue(cell);
objs[j - 1] = cellValue;
}
ContractProduct contractProduct = new ContractProduct(objs);
//7 补全信息
contractProduct.setId(UUID.randomUUID().toString());
contractProduct.setContractId(contractId);
contractProduct.setCompanyId(getCompanyId());
contractProduct.setCompanyName(getCompanyName());

FactoryExample factoryExample = new FactoryExample();
factoryExample.createCriteria().andFactoryNameEqualTo(contractProduct.getFactoryName());
List<Factory> factories = factoryService.findAll(factoryExample);
contractProduct.setFactoryId(factories.get(0).getId());

//8. 封装一个List集合对象
list.add(contractProduct);
}

//9 调用service保存
contractProductService.patchSave(list);

//10 跳转页面
return "redirect:/cargo/contractProduct/list.do?contractId=" + contractId;
}


//解析每个单元格的数据
public static Object getCellValue(Cell cell) {
Object obj = null;
CellType cellType = cell.getCellType(); //获取单元格数据类型
switch (cellType) {
case STRING: {
obj = cell.getStringCellValue();//字符串
break;
}
//excel默认将日期也理解为数字
case NUMERIC: {
if (DateUtil.isCellDateFormatted(cell)) {
obj = cell.getDateCellValue();//日期
} else {
obj = cell.getNumericCellValue(); // 数字
}
break;
}
case BOOLEAN: {
obj = cell.getBooleanCellValue(); // 布尔
break;
}
default: {
break;
}
}
return obj;
}
3.2 ContractProductService
void patchSave(List<ContractProduct> list);
3.3 ContractProductServiceImpl
@Override
public void patchSave(List<ContractProduct> list) {
for (ContractProduct contractProduct : list) {
this.save(contractProduct);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.YHL

谢谢您的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值