add file api

This commit is contained in:
Shaun Chyxion 2018-03-13 22:27:29 +08:00
parent bfe5309b2d
commit a27752c0b3
20 changed files with 498 additions and 13 deletions

View File

@ -25,6 +25,10 @@
<groupId>com.pudonghot.ambition</groupId>
<artifactId>util</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.ambition</groupId>
<artifactId>file-disk</artifactId>
</dependency>
<dependency>
<groupId>com.pudonghot.ambition</groupId>
<artifactId>crm-mapper</artifactId>

View File

@ -0,0 +1,114 @@
package com.pudonghot.ambition.crm.controller;
import javax.validation.Valid;
import me.chyxion.tigon.mybatis.Search;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import me.chyxion.tigon.model.ViewModel;
import me.chyxion.tigon.model.ListResult;
import org.apache.commons.lang3.StringUtils;
import com.pudonghot.ambition.crm.model.User;
import org.springframework.stereotype.Controller;
import com.pudonghot.ambition.crm.model.Application;
import org.springframework.web.multipart.MultipartFile;
import org.apache.shiro.authz.annotation.RequiresRoles;
import com.pudonghot.ambition.crm.model.CustomerProperty;
import org.springframework.web.bind.annotation.RequestParam;
import com.pudonghot.ambition.crm.service.ApplicationService;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestMapping;
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Jun 23, 2017 21:39:49
*/
@Controller
@RequestMapping("/application")
public class ApplicationController
extends BaseQueryController<Application> {
@RequestMapping("/list")
public ListResult<ViewModel<Application>> list(
@Min(0)
@RequestParam(value = "start", defaultValue = "0")
final int start,
@Min(1)
@Max(2048)
@RequestParam(value = "limit", defaultValue = "16")
final int limit,
@RequestParam(value = "search", required = false)
final String strSearch) {
final Search search = new Search().asc(Application.NAME);
final User user = getAuthUser().getUser().getData();
if (!user.isAdmin()) {
search.eq(Application.OWNER, user.getId());
}
return listViewModels(search, start, limit, strSearch, null);
}
@RequestMapping("/list-for-select")
public ListResult<ViewModel<Application>> listForSelect(
@RequestParam(value = "enabled", required = false)
final String enabled,
@RequestParam(value = "search", required = false)
final String strSearch) {
final Search search = new Search().asc(CustomerProperty.NAME);
if (StringUtils.isNotBlank(enabled)) {
search.eq(CustomerProperty.ENABLED, Boolean.parseBoolean(enabled));
}
return listViewModels(search, null, null, strSearch, null);
}
@RequiresRoles(User.ROLE_ADMIN)
@RequestMapping(value = "/create", method = RequestMethod.POST)
public void create(
@Valid ApplicationFormForCreate form) {
((ApplicationService) queryService).create(form, null);
}
@RequiresRoles(User.ROLE_ADMIN)
@RequestMapping(value = "/create-with-images", method = RequestMethod.POST)
public void create(
@Valid
ApplicationFormForCreate form,
@RequestParam("images")
MultipartFile[] images) {
((ApplicationService) queryService).create(form, images);
}
@RequiresRoles(User.ROLE_ADMIN)
@RequestMapping(value = "/update", method = RequestMethod.POST)
public void update(
@Valid ApplicationFormForUpdate form) {
((ApplicationService) queryService).update(form, null);
}
@RequiresRoles(User.ROLE_ADMIN)
@RequestMapping(value = "/update-with-images", method = RequestMethod.POST)
public void update(
@Valid ApplicationFormForUpdate form,
@RequestParam("images")
MultipartFile[] images) {
((ApplicationService) queryService).update(form, images);
}
/**
* {@inheritDoc}
*/
@Override
protected String[] searchCols() {
return new String[] {
CustomerProperty.NAME,
CustomerProperty.NOTE
};
}
}

View File

@ -0,0 +1,53 @@
package com.pudonghot.ambition.crm.controller;
import java.io.File;
import lombok.extern.slf4j.Slf4j;
import me.chyxion.tigon.mybatis.Search;
import org.springframework.util.Assert;
import me.chyxion.tigon.webmvc.ResourceModel;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import com.pudonghot.ambition.crm.model.FileInfo;
import com.pudonghot.ambition.file.AmbitionFileApi;
import com.pudonghot.ambition.crm.mapper.FileInfoMapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @version 0.0.1
* @since 0.0.1
* @author Auto Generated <br>
* Tech Support <a href="mailto:chyxion@163.com">Shaun Chyxion</a><br>
* Sep 14, 2016 3:53:04 PM
*/
@Slf4j
@Controller
public class FileController {
@Autowired
private FileInfoMapper fileInfoMapper;
@Autowired
private AmbitionFileApi fileApi;
@RequestMapping("/f/**")
public Object file(HttpServletRequest request) {
String reqUri = request.getRequestURI();
Assert.state(reqUri.length() > 3, "File name could not be blank");
String fileName = reqUri.substring((request.getContextPath() + "/f/").length());
log.info("Get file [{}].", fileName);
final FileInfo fileInfo = fileInfoMapper.find(new Search(FileInfo.NAME,
fileName.replaceAll("\\.\\w+$", "")));
ResourceModel rm = null;
if (fileInfo != null) {
File file = fileApi.getFile(fileName);
if (file.exists()) {
rm = new ResourceModel(file,
fileInfo.getContentType(), null);
rm.setName(fileInfo.getDownloadName());
}
}
return rm != null ?
rm : ResponseEntity.notFound().build();
}
}

View File

@ -0,0 +1,24 @@
package com.pudonghot.ambition.crm.service;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
import me.chyxion.tigon.service.BaseCrudService;
import com.pudonghot.ambition.crm.model.Application;
import org.springframework.web.multipart.MultipartFile;
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Jun 23, 2017 21:35:24
*/
public interface ApplicationService
extends BaseCrudService<String, Application> {
void create(@NotNull @Valid ApplicationFormForCreate form, MultipartFile[] images);
void update(@NotNull @Valid ApplicationFormForUpdate form, MultipartFile[] images);
}

View File

@ -0,0 +1,85 @@
package com.pudonghot.ambition.crm.service.support;
import java.util.Date;
import java.io.IOException;
import java.io.InputStream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.pudonghot.ambition.file.AmbitionFileApi;
import com.pudonghot.ambition.crm.model.Application;
import org.springframework.web.multipart.MultipartFile;
import com.pudonghot.ambition.crm.model.ApplicationImage;
import com.pudonghot.ambition.crm.mapper.ApplicationMapper;
import com.pudonghot.ambition.crm.service.ApplicationService;
import org.springframework.beans.factory.annotation.Autowired;
import me.chyxion.tigon.service.support.BaseCrudServiceSupport;
import com.pudonghot.ambition.crm.mapper.ApplicationImageMapper;
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Jun 23, 2017 21:36:31
*/
@Slf4j
@Service
public class ApplicationServiceSupport
extends BaseCrudServiceSupport<String, Application, ApplicationMapper>
implements ApplicationService {
@Autowired
private ApplicationImageMapper imageMapper;
@Autowired
private AmbitionFileApi fileApi;
/**
* {@inheritDoc}
*/
@Override
public void create(final ApplicationFormForCreate form, final MultipartFile[] images) {
final String id = idSeq.get();
final Application application = form.copy(new Application());
application.setId(id);
final Date now = new Date();
application.setDateUpdated(now);
if (images != null) {
final String createdBy = form.getCreatedBy();
int sort = 0;
final String imageFolder = imageFolder(id);
for (final MultipartFile image : images) {
if (!image.isEmpty()) {
try (final InputStream ins = image.getInputStream()) {
final String imageId = idSeq.get();
fileApi.uploadImage(ins, imageFolder, imageId);
final ApplicationImage appImage = new ApplicationImage();
appImage.setId(imageId);
appImage.setApplicationId(id);
appImage.setSort(sort++);
appImage.setCreatedBy(createdBy);
appImage.setDateCreated(now);
imageMapper.insert(appImage);
}
catch (IOException e) {
throw new IllegalStateException(
"Read upload image [" + image.getOriginalFilename() + "] error cased", e);
}
}
}
}
mapper.insert(application);
}
/**
* {@inheritDoc}
*/
@Override
public void update(final ApplicationFormForUpdate form, final MultipartFile[] images) {
}
private String imageFolder(final String appId) {
return "app/" + appId;
}
}

View File

@ -16,3 +16,7 @@ shiro.session.validation.scheduler.enabled=true
spring.http.multipart.max-file-size=1024MB
spring.http.multipart.max-request-size=1024MB
# File
file.base-path=http://127.0.0.1:${server.port}/f/
file.base-dir=/Users/chyxion/Workspaces/ambition-crm/files/

View File

@ -2,4 +2,5 @@
/=anon
/index.html=anon
/assets/**=anon
/f/**=anon
/**=user

View File

@ -0,0 +1,33 @@
package com.pudonghot.ambition.crm.service;
import java.io.File;
import org.junit.Test;
import org.junit.runner.RunWith;
import lombok.extern.slf4j.Slf4j;
import com.pudonghot.ambition.crm.AmbitionCRM;
import com.pudonghot.ambition.file.AmbitionFileApi;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 17:07:06
*/
@Slf4j
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AmbitionCRM.class)
public class DiskFileStoreTest {
@Autowired
private AmbitionFileApi fileApi;
@Test
public void testUpload() throws Exception {
final String foobar = fileApi.upload(new File("/Users/chyxion/Workspaces//Eclipse/Default/bzush-schoolmate-api/src/main/java/cn/edu/bzu/schoolmate/controllers/FileController.java"), "foobar");
log.info("Upload result [{}].", foobar);
}
}

View File

@ -37,6 +37,11 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>

View File

@ -9,6 +9,7 @@ import java.util.LinkedList;
import javax.imageio.ImageIO;
import java.io.FileInputStream;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -30,10 +31,8 @@ import org.springframework.beans.factory.annotation.Autowired;
* chyxion@163.com <br>
* Sep 14, 2016 3:31:52 PM
*/
@Slf4j
public abstract class AbstractAmbitionFileApi implements AmbitionFileApi {
private static final Logger log =
LoggerFactory.getLogger(AbstractAmbitionFileApi.class);
@Autowired
protected ImageTool imageTool;
@Autowired

View File

@ -0,0 +1,9 @@
package com.pudonghot.ambition.file.disk;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 18:13:51
*/
public interface DiskFileApi {
}

View File

@ -33,7 +33,7 @@ public class DiskFileSupport
@Autowired
private FileInfoMapper fileInfoMapper;
@Value("${file.server.base-path}")
@Value("${file.base-path}")
private String basePath;
@Value("${file.base-dir}")
private String baseDir;
@ -101,7 +101,7 @@ public class DiskFileSupport
update = true;
// delete previous file
prevFile = new File(getFileDir(), fileInfo.getFilePath());
log.info("Will Delete Previous File [{}].", prevFile);
log.info("Will delete previous file [{}].", prevFile);
}
else {
fileInfo = new FileInfo();
@ -127,13 +127,13 @@ public class DiskFileSupport
}
// File
log.info("Upload Input Stream With Name [{}].", fullName);
log.info("Upload input stream with name [{}].", fullName);
OutputStream fout = null;
try {
// delete previous files
if (prevFile != null) {
FileUtils.deleteQuietly(prevFile);
log.info("Delete File [{}] Before Upload.", prevFile);
log.info("Delete file [{}] before upload.", prevFile);
FileUtils.deleteQuietly(prevFile);
}
@ -151,11 +151,12 @@ public class DiskFileSupport
fout = new FileOutputStream(storeFile);
IOUtils.copy(in, fout);
return getUrl(filePath);
// return getUrl(filePath);
return basePath + fullName;
}
catch (IOException e) {
throw new IllegalStateException(
"Upload File [" + fullName + "] Error Caused", e);
"Upload file [" + fullName + "] error caused", e);
}
finally {
IOUtils.closeQuietly(fout);
@ -168,10 +169,10 @@ public class DiskFileSupport
*/
@Override
public File getFile(final String name) {
FileInfo fileInfo = fileInfoMapper.find(nameSearch(name));
final FileInfo fileInfo = fileInfoMapper.find(nameSearch(name));
Assert.state(fileInfo != null,
"No File [" + name + "] Found");
return getFile(name, fileInfo.getFormat());
return getFile(fileInfo.getFilePath(), fileInfo.getFormat());
}
/**
@ -242,9 +243,9 @@ public class DiskFileSupport
}
String fullName = null;
if (StringUtils.isNotBlank(name)) {
log.debug("Name [{}] Is Not Blank.", name);
log.debug("Name [{}] is not blank.", name);
if (name.startsWith(basePath)) {
log.debug("Name Starts With Base Path [{}], Trim.", basePath);
log.debug("Name starts with base path [{}], trim.", basePath);
fullName = name.replaceFirst(basePath, "");
}
else if (StringUtils.isNotBlank(folder)) {

View File

@ -0,0 +1,13 @@
package com.pudonghot.ambition.crm.mapper;
import me.chyxion.tigon.mybatis.BaseMapper;
import com.pudonghot.ambition.crm.model.ApplicationImage;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 11:39:49
*/
public interface ApplicationImageMapper extends BaseMapper<String, ApplicationImage> {
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 11:39:14
*/
-->
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationImageMapper">
</mapper>

View File

@ -0,0 +1,13 @@
package com.pudonghot.ambition.crm.mapper;
import me.chyxion.tigon.mybatis.BaseMapper;
import com.pudonghot.ambition.crm.model.Application;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 11:39:28
*/
public interface ApplicationMapper extends BaseMapper<String, Application> {
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 06, 2018 22:49:18
*/
-->
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationMapper">
</mapper>

View File

@ -0,0 +1,23 @@
package com.pudonghot.ambition.crm.form.create;
import lombok.Getter;
import lombok.Setter;
import me.chyxion.tigon.form.FC2;
import org.hibernate.validator.constraints.NotBlank;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 11, 2018 11:14:07
*/
@Getter
@Setter
public class ApplicationFormForCreate extends FC2<String> {
private static final long serialVersionUID = 1L;
// Properties
@NotBlank
private String name;
private String content;
private String owner;
}

View File

@ -0,0 +1,24 @@
package com.pudonghot.ambition.crm.form.update;
import lombok.Getter;
import lombok.Setter;
import me.chyxion.tigon.form.FU2;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
/**
* @version 0.0.1
* @since 0.0.1
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* May 10, 2016 1:42:01 PM
*/
@Getter
@Setter
public class ApplicationFormForUpdate extends FU2<String, String> {
private static final long serialVersionUID = 1L;
@NotBlank
@Length(max = 64)
private String name;
}

View File

@ -0,0 +1,28 @@
package com.pudonghot.ambition.crm.model;
import lombok.Getter;
import lombok.Setter;
import me.chyxion.tigon.model.M3;
import me.chyxion.tigon.mybatis.Table;
/**
* @author Donghuang <br>
* donghuang@wacai.com <br>
* Mar 06, 2018 22:48:13
*/
@Getter
@Setter
@Table("crm_application")
public class Application extends M3<String, String> {
private static final long serialVersionUID = 1L;
// Column Names
public static final String NAME = "name";
public static final String CONTENT = "content";
public static final String OWNER = "owner";
// Properties
private String name;
private String content;
private String owner;
}

View File

@ -0,0 +1,26 @@
package com.pudonghot.ambition.crm.model;
import lombok.Getter;
import lombok.Setter;
import me.chyxion.tigon.model.M3;
import me.chyxion.tigon.mybatis.Table;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
* Mar 06, 2018 22:50:08
*/
@Getter
@Setter
@Table("crm_application_image")
public class ApplicationImage extends M3<String, String> {
private static final long serialVersionUID = 1L;
// Column Names
public static final String APPLICATION_ID = "application_id";
public static final String SORT = "sort";
// Properties
private String applicationId;
private int sort;
}