基于javaweb+mysql的springboot线上网络文件管理系统(java+springboot+html+ssm+maven+mysql)
私信源码获取及调试交流
运行环境
Java≥8、MySQL≥5.7
开发工具
eclipse/idea/myeclipse/sts等均可配置运行
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb的SpringBoot线上网络文件管理系统(java+springboot+html+ssm+maven+mysql)
项目介绍
本项目分为前后台,有管理员与用户两种角色;
管理员角色包含以下功能:
管理员登录,管理员主页,权限管理,分类管理,用户管理,文档管理,下载记录,上传记录等功能。 用户角色包含以下功能:
注册账号,登录,系统首页,我的资源查看,编辑资源,我的资料修改,文件上传,密码重置,邮箱信息,密码重置成功等功能。
环境需要
1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。
2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;
3.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS;
4.数据库:MySql 8.0/5.7版本;
技术栈
HTML+CSS+JavaScript+mysql+Spring+SpringMVC+mybatis+Spring boot
使用说明
运行项目,输入http://localhost:8091 登录
/**
*/
@Service
public class FileManagerServiceImpl implements IFileManagerService {
private static Logger logger = Logger.getLogger(FileManagerServiceImpl.class);
@Override
public void multiDownload(HttpServletResponse response, String[] items, String destFile) throws IOException {
File zip = ZipUtil.zip(new File(ValueConsts.USER_DESKTOP + File.separator + destFile), ValueConsts.FALSE,
FileExecutor.getFiles(items));
if (zip.exists()) {
response.getOutputStream().write(FileExecutor.readFileToByteArray(zip));
FileExecutor.deleteFile(zip);
}
}
@Override
public JSONObject upload(String destination, MultipartFile... files) {
System.out.println(files.length);
if (Checker.isNotEmpty(files)) {
if (Checker.isWindows() && destination.length() < ValueConsts.TWO_INT) {
destination = "C:";
}
for (MultipartFile file : files) {
if (Checker.isNotNull(file) && !file.isEmpty()) {
try {
* 用过用户名获取用户Id
*
* @param usernameOrEmail 用户名或邮箱
*
* @return 用户编号
*/
int getUserId(String usernameOrEmail);
}
/**
*/
public class WebInterceptor implements HandlerInterceptor {
@Autowired
UserServiceImpl userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
Exception {
String url = request.getServletPath();
InterceptorLevel level = InterceptorLevel.NONE;
if (handler instanceof HandlerMethod) {
AuthInterceptor interceptor = ((HandlerMethod) handler).getMethodAnnotation(AuthInterceptor.class);
//注解到类上面的注解,无法直接获取,只能通过扫描
/**
*/
@Service
public class FileServiceImpl implements IFileService {
private final static Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);
private static final String FILE_SUFFIX = "{fileSuffix}";
private static final String RANDOM_ID = "{randomId}";
private static final String YEAR = "{year}";
private static final String MONTH = "{month}";
private static final String DAY = "{day}";
private static final String AUTHOR = "{author}";
private static final String FILE_NAME = "{fileName}";
private static final String CATEGORY_NAME = "{categoryName}";
private final FileDAO fileDAO;
private final ICategoryService categoryService;
private final IAuthService authService;
private final DownloadedDAO downloadDAO;
@Autowired
public FileServiceImpl(FileDAO fileDAO, ICategoryService categoryService, IAuthService authService,
DownloadedDAO downloadDAO) {
this.fileDAO = fileDAO;
RequestMapping mapping = type.getAnnotation(RequestMapping.class);
if (Checker.isNotNull(mapping)) {
for (String path : mapping.value()) {
if (url.startsWith(path)) {
interceptor = type.getAnnotation(AuthInterceptor.class);
break;
}
}
break;
}
}
}
if (Checker.isNotNull(interceptor)) {
level = interceptor.value();
}
}
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
if (Checker.isNull(user)) {
//读取token,自动登录
Cookie cookie = HttpUtils.getCookie(ValueConsts.TOKEN_STRING, request.getCookies());
if (Checker.isNotNull(cookie)) {
user = userService.login(ValueConsts.EMPTY_STRING, ValueConsts.EMPTY_STRING, cookie.getValue(),
response);
if (Checker.isNotNull(user)) {
request.getSession().setAttribute(ValueConsts.USER_STRING, user);
}
}
}
if (level != InterceptorLevel.NONE) {
boolean isRedirect = Checker.isNull(user) || (level == InterceptorLevel.ADMIN && user.getPermission() <
2) || (level == InterceptorLevel.SYSTEM && user.getPermission() < 3);
if (isRedirect) {
response.sendRedirect(DefaultValues.SIGNIN_PAGE);
return false;
}
}
return true;
}
}
@RequestMapping(value = "/content", method = RequestMethod.POST)
public String getContent(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.getContent(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/edit", method = RequestMethod.POST)
public String edit(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.edit(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/remove", method = RequestMethod.POST)
public String remove(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.remove(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/copy", method = RequestMethod.POST)
public String copy(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.copy(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/move", method = RequestMethod.POST)
public String move(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.move(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/rename", method = RequestMethod.POST)
public String rename(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.rename(json));
return jsonObject.toJSONString();
}
@AuthInterceptor(InterceptorLevel.SYSTEM)
@RequestMapping(value = "/list", method = RequestMethod.POST)
public String list(@RequestBody JSONObject json) {
jsonObject.put("result", fileManagerService.list(json));
return jsonObject.toJSONString();
}
}
/**
*/
@RestController
@RequestMapping("/config")
@Api(value = "/config", description = "配置文件的相关操作")
public class ConfigController {
private static Logger logger = Logger.getLogger(ConfigController.class);
private final IConfigService configService;
private final HttpServletRequest request;
@Autowired
public ConfigController(IConfigService configService, HttpServletRequest request) {
this.configService = configService;
this.request = request;
}
@ApiOperation(value = "更新配置文件")
@ApiImplicitParam(name = "config", value = "配置文件内容", required = true)
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "", method = RequestMethod.PUT)
public String updateConfig(String config) {
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
if (user.getPermission() > ValueConsts.TWO_INT) {
StartApplication.settings.setJsonObject(config);
//打包成jar之后无法修改config.json文件
try {
FileExecutor.saveFile(NetUtils.urlToString(StartApplication.class.getResource(DefaultValues
.SETTING_PATH)), StartApplication.settings.toString());
} catch (IOException e) {
logger.error(e.getMessage());
return "{\"message\":\"internal error, cannot save\"}";
}
return "{\"message\":\"saved successfully\"}";
} else {
return "{\"message\":\"permission denied\"}";
* 移动文件
*
* @param object {@link JSONObject}
*
* @return {@link JSONObject}
*/
JSONObject move(JSONObject object);
/**
* 重命名
*
* @param object {@link JSONObject}
*
* @return {@link JSONObject}
*/
JSONObject rename(JSONObject object);
/**
* 列出文件
*
* @param object {@link JSONObject}
*
* @return {@link JSONObject}
*/
JSONArray list(JSONObject object);
}
/**
*/
@Controller
@Api(description = "视图页面映射")
public class ViewController {
private final HttpServletRequest request;
/**
*/
@RestController
@RequestMapping("/file")
@Api(value = "/file", description = "文件相关操作")
public class FileController {
private final IFileService fileService;
private final HttpServletRequest request;
private final JSONObject jsonObject;
@Autowired
public FileController(IFileService fileService, HttpServletRequest request, JSONObject jsonObject) {
this.fileService = fileService;
public boolean removeById(long id) {
downloadDAO.removeByFileId(id);
authService.removeByFileId(id);
return fileDAO.removeById(id);
}
@Override
public boolean removeByVisitUrl(String visitUrl) {
long fileId = fileDAO.getIdByVisitUrl(visitUrl);
return removeById(fileId);
}
@Override
public boolean removeByLocalUrl(String localUrl) {
long fileId = fileDAO.getIdByLocalUrl(localUrl);
return removeById(fileId);
}
@Override
public String getResource(String visitUrl, HttpServletRequest request) {
logger.info("visit url: " + visitUrl);
boolean downloadable = StartApplication.settings.getBooleanUseEval(ConfigConsts
.ANONYMOUS_DOWNLOADABLE_OF_SETTING);
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
File file = fileDAO.getFileByVisitUrl(visitUrl);
AuthRecord authRecord = null;
if (Checker.isNotNull(file)) {
authRecord = authService.getByFileIdAndUserId(file.getId(), Checker.isNull(user) ? 0 : user.getId());
}
boolean canDownload = Checker.isNotNull(file) && file.getIsDownloadable() == 1 && (downloadable || (Checker
.isNull(authRecord) ? (Checker.isNotNull(user) && user.getIsDownloadable() == 1) : authRecord
.getIsDownloadable() == 1));
if (canDownload) {
fileDAO.updateDownloadTimesById(file.getId());
if (Checker.isNotNull(user)) {
downloadDAO.insertDownload(user.getId(), file.getId());
}
return file.getLocalUrl();
}
return "";
}
@Override
public String getLocalUrlByVisitUrl(String visitUrl) {
return fileDAO.getLocalUrlByVisitUrl(Checker.checkNull(visitUrl));
}
@Override
public List<FileRecord> listAll(int userId, int offset, int categoryId, String orderBy, String search) {
return fileDAO.listAll(userId, offset, categoryId, orderBy, search);
}
@Override
} else {
jsonObject.put("message", "更新失败,请稍后重新尝试");
}
return jsonObject.toJSONString();
}
@ApiOperation("重置用户密码(管理员接口)")
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "/reset/{id}/{password}", method = RequestMethod.PUT)
public String resetPassword(@PathVariable("id") int id, @PathVariable("password") String password) {
return ControllerUtils.getResponse(userService.resetPassword(id, password));
}
@ApiOperation(value = "更新用户的默认文件权限")
@ApiImplicitParam(name = "auth", value = "权限", example = "1,1,1,1", required = true)
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "/{id}/auth", method = RequestMethod.PUT)
public String updateFileAuth(@PathVariable("id") int id, String auth) {
return ControllerUtils.getResponse(userService.updateFileAuth(id, auth));
}
@ApiOperation(value = "获取所有用户")
@ApiImplicitParams({@ApiImplicitParam(name = "user", value = "指定用户(默认所有用户)"), @ApiImplicitParam(name = "offset",
value = "偏移量", required = true)})
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "/all", method = RequestMethod.GET)
public String getUser(String user, int offset) {
User u = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
return Formatter.listToJson(userService.listUser(u.getPermission(), user, offset));
}
@ApiOperation(value = "更新我的基本信息")
@ApiImplicitParams({@ApiImplicitParam(name = "avatar", value = "头像(可空)"), @ApiImplicitParam(name = "realName",
value = "真实姓名(可空)"), @ApiImplicitParam(name = "email", value = "邮箱(可空)"), @ApiImplicitParam(name =
"code", value = "验证码(可空)")})
@AuthInterceptor(InterceptorLevel.USER)
@RequestMapping(value = "/info", method = RequestMethod.PUT)
public String updateBasicInfo(String avatar, String realName, String email, String code) {
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
jsonObject.put("message", "保存成功");
boolean emilVerify = StartApplication.settings.getBooleanUseEval(ConfigConsts.EMAIL_VERIFY_OF_SETTINGS);
if (Checker.isNotEmpty(email) && !email.equals(user.getEmail())) {
if (!emilVerify || isCodeValidate(code)) {
if (userService.emailExists(email)) {
jsonObject.put("message", "邮箱更新失败,该邮箱已经存在");
} else {
user.setEmail(email);
}
} else {
jsonObject.put("message", "邮箱更新失败,验证码校验失败");
}
}
if (userService.updateBasicInfoById(user.getId(), avatar, realName, user.getEmail())) {
}
break;
}
}
}
if (Checker.isNotNull(interceptor)) {
level = interceptor.value();
}
}
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
if (Checker.isNull(user)) {
//读取token,自动登录
Cookie cookie = HttpUtils.getCookie(ValueConsts.TOKEN_STRING, request.getCookies());
if (Checker.isNotNull(cookie)) {
user = userService.login(ValueConsts.EMPTY_STRING, ValueConsts.EMPTY_STRING, cookie.getValue(),
response);
if (Checker.isNotNull(user)) {
request.getSession().setAttribute(ValueConsts.USER_STRING, user);
}
}
}
if (level != InterceptorLevel.NONE) {
boolean isRedirect = Checker.isNull(user) || (level == InterceptorLevel.ADMIN && user.getPermission() <
2) || (level == InterceptorLevel.SYSTEM && user.getPermission() < 3);
if (isRedirect) {
response.sendRedirect(DefaultValues.SIGNIN_PAGE);
return false;
}
}
return true;
}
}
@ApiOperation(value = "更新用户的默认文件权限")
@ApiImplicitParam(name = "auth", value = "权限", example = "1,1,1,1", required = true)
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "/{id}/auth", method = RequestMethod.PUT)
public String updateFileAuth(@PathVariable("id") int id, String auth) {
return ControllerUtils.getResponse(userService.updateFileAuth(id, auth));
}
@ApiOperation(value = "获取所有用户")
@ApiImplicitParams({@ApiImplicitParam(name = "user", value = "指定用户(默认所有用户)"), @ApiImplicitParam(name = "offset",
value = "偏移量", required = true)})
@AuthInterceptor(InterceptorLevel.ADMIN)
@RequestMapping(value = "/all", method = RequestMethod.GET)
public String getUser(String user, int offset) {
User u = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
return Formatter.listToJson(userService.listUser(u.getPermission(), user, offset));
}
@ApiOperation(value = "更新我的基本信息")
@ApiImplicitParams({@ApiImplicitParam(name = "avatar", value = "头像(可空)"), @ApiImplicitParam(name = "realName",
value = "真实姓名(可空)"), @ApiImplicitParam(name = "email", value = "邮箱(可空)"), @ApiImplicitParam(name =
"code", value = "验证码(可空)")})
@AuthInterceptor(InterceptorLevel.USER)
@RequestMapping(value = "/info", method = RequestMethod.PUT)
public String updateBasicInfo(String avatar, String realName, String email, String code) {
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
jsonObject.put("message", "保存成功");
boolean emilVerify = StartApplication.settings.getBooleanUseEval(ConfigConsts.EMAIL_VERIFY_OF_SETTINGS);
if (Checker.isNotEmpty(email) && !email.equals(user.getEmail())) {
if (!emilVerify || isCodeValidate(code)) {
if (userService.emailExists(email)) {
jsonObject.put("message", "邮箱更新失败,该邮箱已经存在");
} else {
user.setEmail(email);
}
} else {
jsonObject.put("message", "邮箱更新失败,验证码校验失败");
}
}
@Override
public List<FileBasicRecord> listBasicAll(String user, String file, String category, int offset) {
return (List<FileBasicRecord>) ServiceUtils.invokeFileFilter(fileDAO, "listBasicBy", user, file, category,
offset);
}
}
/**
} catch (Exception e) {
FileExecutor.deleteFile(localUrl);
logger.error("save file error: " + e.getMessage());
}
}
}
return false;
}
private String getRegularVisitUrl(String customUrl, User user, String fileName, String suffix, Category category) {
Date date = new Date();
suffix = suffix.startsWith(".") ? "" : "." + suffix;
if (Checker.isNotEmpty(customUrl)) {
try {
customUrl = URLDecoder.decode(customUrl, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage());
}
}
if (!customUrl.contains(FILE_NAME) && !customUrl.contains(RANDOM_ID)) {
customUrl += (customUrl.endsWith("/") ? "" : "/") + fileName;
}
customUrl = customUrl.replace(YEAR, DateUtils.getYear(date)).replace(MONTH, DateUtils.getMonth(date)).replace
(DAY, DateUtils.getDay(date)).replace(AUTHOR, user.getUsername()).replace(FILE_NAME, fileName)
.replace(CATEGORY_NAME, Checker.checkNull(Checker.isNull(category) ? "uncategorized" : category
.getName())).replace(RANDOM_ID, String.valueOf(RandomUtils.getRandomInteger(ValueConsts
.NINE_INT))).replace(FILE_SUFFIX, suffix);
return "/file" + (customUrl.startsWith("/") ? "" : "/") + customUrl;
}
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor =
Exception.class)
public boolean shareFiles(String prefix, String files, User user) {
if (Checker.isNotEmpty(files)) {
String[] paths = files.split(ValueConsts.COMMA_SIGN);
for (String path : paths) {
java.io.File f = new java.io.File(path);
String name = f.getName();
String suffix = FileExecutor.getFileSuffix(name);
String visitUrl = getRegularVisitUrl(prefix, user, name, suffix, null);
if (f.exists() && f.isFile() && !localUrlExists(path) && !visitUrlExists(visitUrl)) {
File file = new File(name, suffix, path, visitUrl, ValueConsts.EMPTY_STRING,
ValueConsts.EMPTY_STRING, user.getId(),
categoryService.getIdByName(DefaultValues.UNCATEGORIZED));
file.setAuth(ValueConsts.ONE_INT, ValueConsts.ZERO_INT, ValueConsts.ZERO_INT,
ValueConsts.ZERO_INT, ValueConsts.ONE_INT);
} else {
jsonObject.put("message", "原密码不正确");
}
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
jsonObject.put("message", "服务器内部错误,请稍后重新尝试");
}
return jsonObject.toString();
}
@ApiOperation(value = "获取我的基本信息")
@AuthInterceptor(InterceptorLevel.USER)
@RequestMapping(value = "/info", method = RequestMethod.GET)
public String getInfo() {
User user = (User) request.getSession().getAttribute(ValueConsts.USER_STRING);
JSONObject object = JSON.parseObject(user.toString());
object.remove(ValueConsts.ID_STRING);
object.remove(ValueConsts.PASSWORD_STRING);
return object.toString();
}
@ApiOperation(value = "登录(用户名密码和token必须有一个输入)")
@ApiImplicitParams({@ApiImplicitParam(name = "username", value = "用户名"), @ApiImplicitParam(name
= "password", value = "密码"), @ApiImplicitParam(name = "auto", value = "是否自动登录", dataType = "Boolean"),
@ApiImplicitParam(name = "token", value = "用于自动登录")})
@AuthInterceptor(InterceptorLevel.NONE)
@RequestMapping(value = "/login", method = RequestMethod.PUT)
public String login(String username, String password, boolean auto, String token) {
//使用密码登录
User user = userService.login(username, password, ValueConsts.NULL_STRING, ValueConsts.NULL_RESPONSE);
if (Checker.isNull(user) || user.getPermission() < 1) {
jsonObject.put("status", "failed");
} else {
request.getSession().setAttribute(ValueConsts.USER_STRING, user);
jsonObject.put("status", "success");
if (auto) {
jsonObject.put("token", TokenConfig.generateToken(token, user.getId()));
} else {
jsonObject.put("token", "");
TokenConfig.removeTokenByValue(user.getId());
}
}
return jsonObject.toString();
}
@ApiOperation(value = "用户注册(当不需要验证邮箱时,邮箱和验证码可空)")
@ApiImplicitParams({@ApiImplicitParam(name = "username", value = "用户名", required = true), @ApiImplicitParam(name
= "email", value = "邮箱"), @ApiImplicitParam(name = "password", value = "密码", required = true),
List<FileRecord> listUserDownloaded(int userId, int offset, String search);
/**
* 获取用户的上传资源
*
* @param userId 用户编号
* @param offset 偏移
* @param search 搜索
*
* @return {@link List}
*/
List<FileRecord> listUserUploaded(int userId, int offset, String search);
/**
* 通过编号删除,不验证权限
*
* @param id 编号
*
* @return 是否删除成功
*/
boolean removeById(long id);
/**
* 通过访问路径删除
*
* @param visitUrl 访问路径
*
* @return 是否删除成功
*/
boolean removeByVisitUrl(String visitUrl);
/**
* 通过本地路径删除
*
* @param localUrl 访问路径
*
* @return 是否删除成功
*/
boolean removeByLocalUrl(String localUrl);
/**
* 获取资源
*
* @param visitUrl 访问路径
* @param request {@link HttpServletRequest}
*
* @return {@link File}
*/
String getResource(String visitUrl, HttpServletRequest request);
/**
* 通过访问路径获取本地文件路径
/**
*/
@RestController
@RequestMapping("/file")
@Api(value = "/file", description = "文件相关操作")
public class FileController {
private final IFileService fileService;
private final HttpServletRequest request;
private final JSONObject jsonObject;
*/
String getLocalUrlByVisitUrl(String visitUrl);
/**
* 获取所有文件
*
* @param userId 用户编号
* @param offset 偏移
* @param categoryId 分类编号
* @param orderBy 排序方式
* @param search 搜索
*
* @return {@link List}
*/
List<FileRecord> listAll(int userId, int offset, int categoryId, String orderBy, String search);
/**
* 上传文件
*
* @param categoryId 分类ID
* @param tag 标签
* @param description 描述
* @param prefix 自定义前缀
* @param multipartFile 文件
* @param user {@link User}
*
* @return 是否上传成功
*/
boolean upload(int categoryId, String tag, String description, String prefix, MultipartFile multipartFile, User
user);
/**
* 分享服务器本地文件
*
* @param prefix 链接前缀
* @param files 文件
* @param user 用户对象
*
* @return 是否添加成功
*/
boolean shareFiles(String prefix, String files, User user);
/**
* 本地路径是否存在
*
* @param localUrl 本地路径
*
* @return {@link Boolean}
*/
boolean localUrlExists(String localUrl);