Skip to content

Commit

Permalink
Merge pull request #17 from getmoneynote/dev
Browse files Browse the repository at this point in the history
feat: file upload
  • Loading branch information
markliu2013 authored Jan 2, 2024
2 parents 5353429 + 8237126 commit 64d6ab3
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 6 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@

## 主要功能

- 监控个人资产负债。
- 记录个人支出和收入。
- 监控个人资产负债
- 记录个人支出和收入
- 支持账单添加多个附件
- 支持多个账本记账
- 支持多币种
- 支持多种账本模板
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cn.biq.mn.base.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.web.multipart.MultipartFile;

public class FileValidator implements ConstraintValidator<ValidFile, MultipartFile> {

@Override
public void initialize(ValidFile constraintAnnotation) {

}

@Override
public boolean isValid(MultipartFile multipartFile, ConstraintValidatorContext context) {
boolean result = true;
String contentType = multipartFile.getContentType();
if (!isSupportedContentType(contentType)) {
result = false;
}
return result;
}

private boolean isSupportedContentType(String contentType) {
return contentType.equals("application/pdf")
|| contentType.equals("image/png")
|| contentType.equals("image/jpg")
|| contentType.equals("image/jpeg");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cn.biq.mn.base.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.*;

@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {FileValidator.class})
public @interface ValidFile {
String message() default "Only PDF,XML,PNG or JPG images are allowed";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ item.exists.exception=名称已存在
item.not.found.exception=记录不存在
error.parent.itself=父类不能是自己

response.message.success=操作成功
response.message.success=操作成功

auth.error=没有权限
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import cn.biq.mn.user.account.Account;
import cn.biq.mn.user.book.Book;
import cn.biq.mn.user.flowfile.FlowFile;
import cn.biq.mn.user.group.Group;
import cn.biq.mn.user.payee.Payee;
import cn.biq.mn.user.user.User;
Expand Down Expand Up @@ -90,4 +91,7 @@ public class BalanceFlow extends BaseEntity {
@Column(nullable = false, updatable = false)
private Long insertAt = System.currentTimeMillis();

@OneToMany(mappedBy = "flow", fetch = FetchType.LAZY)
private Set<FlowFile> files = new HashSet<>();

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package cn.biq.mn.user.balanceflow;

import cn.biq.mn.base.validation.ValidFile;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import cn.biq.mn.base.response.BaseResponse;
import cn.biq.mn.base.response.PageResponse;
import cn.biq.mn.base.response.DataResponse;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/balance-flows")
Expand Down Expand Up @@ -52,4 +55,14 @@ public BaseResponse handleConfirm(@PathVariable("id") Integer id) {
return new BaseResponse(balanceFlowService.confirm(id));
}

@RequestMapping(method = RequestMethod.POST, value = "/{id}/addFile")
public BaseResponse handleAddFile(@PathVariable("id") Integer id, @Validated @ValidFile @RequestParam("file") MultipartFile file) {
return new DataResponse<>(balanceFlowService.addFile(id, file));
}

@RequestMapping(method = RequestMethod.GET, value = "/{id}/files")
public BaseResponse handleFiles(@PathVariable("id") Integer id) {
return new DataResponse<>(balanceFlowService.getFiles(id));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import cn.biq.mn.user.account.AccountRepository;
import cn.biq.mn.user.base.BaseService;
import cn.biq.mn.user.book.Book;
import cn.biq.mn.user.flowfile.FlowFile;
import cn.biq.mn.user.flowfile.FlowFileDetails;
import cn.biq.mn.user.flowfile.FlowFileMapper;
import cn.biq.mn.user.flowfile.FlowFileRepository;
import cn.biq.mn.user.group.Group;
import cn.biq.mn.user.payee.Payee;
import cn.biq.mn.user.payee.PayeeRepository;
Expand All @@ -25,7 +29,9 @@
import cn.biq.mn.user.categoryrelation.CategoryRelationService;
import cn.biq.mn.user.tagrelation.TagRelation;
import cn.biq.mn.user.tagrelation.TagRelationService;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
Expand All @@ -44,6 +50,7 @@ public class BalanceFlowService {
private final CategoryRelationService categoryRelationService;
private final TagRelationService tagRelationService;
private final BalanceFlowMapper balanceFlowMapper;
private final FlowFileRepository flowFileRepository;

private void checkBeforeAdd(BalanceFlowAddForm form, Book book, User user) {
// 对用户添加账单的操作进行限流。
Expand Down Expand Up @@ -389,4 +396,27 @@ public boolean confirm(Integer id) {
return true;
}

public FlowFileDetails addFile(Integer id, MultipartFile file) {
FlowFile flowFile = new FlowFile();
try {
flowFile.setData(file.getBytes());
} catch (IOException e) {
throw new FailureMessageException("add.flow.file.fail");
}
flowFile.setCreator(sessionUtil.getCurrentUser());
flowFile.setFlow(baseService.findFlowById(id));
flowFile.setCreateTime(System.currentTimeMillis());
flowFile.setSize(file.getSize());
flowFile.setContentType(file.getContentType());
flowFile.setOriginalName(file.getOriginalFilename());
flowFileRepository.save(flowFile);
return FlowFileMapper.toDetails(flowFile);
}

public List<FlowFileDetails> getFiles(Integer id) {
BalanceFlow flow = baseService.findFlowById(id);
List<FlowFile> flowFiles = flowFileRepository.findByFlow(flow);
return flowFiles.stream().map(FlowFileMapper::toDetails).toList();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package cn.biq.mn.user.flowfile;

import cn.biq.mn.base.base.BaseEntity;
import cn.biq.mn.user.balanceflow.BalanceFlow;
import cn.biq.mn.user.user.User;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "t_flow_file")
@Getter
@Setter
public class FlowFile extends BaseEntity {

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(columnDefinition = "LONGBLOB", nullable = false)
private byte[] data;

@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User creator; //上传人

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "flow_id")
private BalanceFlow flow;

@Column(nullable = false)
private Long createTime;

@Column(length = 32, nullable = false)
private String contentType;

@Column(nullable = false)
private Long size;

@Column(length = 512, nullable = false)
private String originalName;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cn.biq.mn.user.flowfile;

import cn.biq.mn.base.base.BaseController;
import cn.biq.mn.base.response.BaseResponse;
import cn.biq.mn.user.utils.SessionUtil;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/flow-files")
@RequiredArgsConstructor
public class FlowFileController extends BaseController {

private final FlowFileService flowFileService;

@RequestMapping(method = RequestMethod.GET, value = "/view")
public ResponseEntity<byte[]> handleView(@Valid FlowFileViewForm form) {
FlowFile flowFile = flowFileService.getFile(form);
return ResponseEntity.ok().contentType(MediaType.parseMediaType(flowFile.getContentType())).body(flowFile.getData());
}

@RequestMapping(method = RequestMethod.DELETE, value = "/{id}")
public BaseResponse handleDelete(@PathVariable("id") Integer id) {
return new BaseResponse(flowFileService.remove(id));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cn.biq.mn.user.flowfile;

import cn.biq.mn.base.base.BaseDetails;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class FlowFileDetails extends BaseDetails {

private Long createTime;
private String contentType;
private Long size;
private String originalName;

public boolean isImage() {
return contentType.equals("image/jpeg") || contentType.equals("image/png");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cn.biq.mn.user.flowfile;


public class FlowFileMapper {

public static FlowFileDetails toDetails(FlowFile entity) {
if (entity == null) return null;
var details = new FlowFileDetails();
details.setId(entity.getId());
details.setCreateTime(entity.getCreateTime());
details.setContentType(entity.getContentType());
details.setSize(entity.getSize());
details.setOriginalName(entity.getOriginalName());
return details;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cn.biq.mn.user.flowfile;

import cn.biq.mn.base.base.BaseRepository;
import cn.biq.mn.user.balanceflow.BalanceFlow;
import org.springframework.stereotype.Repository;

import java.util.List;


@Repository
public interface FlowFileRepository extends BaseRepository<FlowFile> {

List<FlowFile> findByFlow(BalanceFlow flow);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cn.biq.mn.user.flowfile;

import cn.biq.mn.base.exception.FailureMessageException;
import cn.biq.mn.user.balanceflow.BalanceFlow;
import cn.biq.mn.user.base.BaseService;
import cn.biq.mn.user.book.Book;
import cn.biq.mn.user.group.Group;
import cn.biq.mn.user.user.User;
import cn.biq.mn.user.utils.SessionUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class FlowFileService {

private final FlowFileRepository flowFileRepository;
private final SessionUtil sessionUtil;
private final BaseService baseService;

@Transactional(readOnly = true)
public FlowFile getFile(FlowFileViewForm form) {
FlowFile flowFile = flowFileRepository.getReferenceById(form.getId());
if (!flowFile.getCreateTime().equals(form.getCreateTime())) {
throw new FailureMessageException();
}
return flowFile;
}

public boolean remove(Integer id) {
FlowFile flowFile = flowFileRepository.getReferenceById(id);
BalanceFlow flow = baseService.findFlowById(flowFile.getFlow().getId());
if (flow == null) {
throw new FailureMessageException("auth.error");
}
flowFileRepository.delete(flowFile);
return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cn.biq.mn.user.flowfile;

import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;


@Getter @Setter
public class FlowFileViewForm {

@NonNull
private Integer id;

// 时间是为了增加地址的安全性
@NonNull
private Long createTime;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ public class MvcInterceptorConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register", "/loginWechat/**", "/loginGoogle/**", "/version", "/test*");
.excludePathPatterns("/login", "/register")
.excludePathPatterns("/loginWechat/**", "/loginGoogle/**")
.excludePathPatterns("/flow-files/view")
.excludePathPatterns("/version")
.excludePathPatterns("/test*");
WebMvcConfigurer.super.addInterceptors(registry);
}

Expand Down
11 changes: 10 additions & 1 deletion moneynote-api-user/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@ sentry.dsn=https://[email protected]/450
sentry.traces-sample-rate=1.0
#sentry.debug=true

user_api_base_url=https://api.moneywhere.com/api/v1/user-api/
user_api_base_url=https://api.moneywhere.com/api/v1/user-api/


# 文件上传
# 设置内置Tomcat请求大小
server.tomcat.max-http-form-post-size=100MB
# 设置请求最大大小
spring.servlet.multipart.max-request-size=100MB
# 设置文件上传最大大小
spring.servlet.multipart.max-file-size=100MB
Loading

0 comments on commit 64d6ab3

Please sign in to comment.