Java+Springboot搭建一个在线网盘文件分享系统

目录
  • 前言
  • 效果图
  • 主要代码
    • 管理员控制器:
    • 文件仓库控制器:
    • 登录控制器:
    • FTP工具类: 

前言

springboot+freemark+jpa+MySQL实现的在线网盘文件分享系统,其功能跟百度网盘非常类似,普通用户可以注册登录,注册后默认分配1G的空间大小,登录进去后可以新建文件夹、上传各种类型的文件、文件移动、复制、下载、删除、分享,分享分为私密分享和公开分享,还可以设置分享过期时间,打开分享链接后可以对文件进行查看、下载、保存到自己网盘等。超级管理员登录后可以设置普通用户的空间大小、角色类型、权限等。

本系统主要涉及的特色功能有:

1:系统在上传文件时自动计算文件的md5值,并且检查该值是否存在,若存在则文件不再上传到服务器,直接进行引用原有的文件。

2:定时器定时检查限时分享的文件是否过期。

3:网盘目录结构可无限制层级创建,保存移动复制文件时递归所选文件夹层级等等。

使用技术:java+springboot+freemark+jpa+MySQL+maven

效果图

 

 

主要代码

管理员控制器:

/**
 * @ClassName: AdminController
 * @Description: 管理员控制器
 **/
@Controller
public class AdminController extends BaseController {
    private Logger logger = LogUtils.getInstance(AdminController.class);

    /**
     * @Description 前往用户管理页面
     **/
    @GetMapping("/manages-users")
    public String manageUsers(Map<String,Object> map,Integer cur){
        if (loginUser.getRole() == 1){
            //用于无访问权限
            logger.error("当前登录用户:"+loginUser.getUserName()+"无管理员权限!");
            return "redirect:/error401Page";
        }
        //获取全部的用户
        Integer usersCount = userService.getUsersCount();
        //获取当前查询的页数,如果为空,默认为0
        cur = (cur == null || cur<0)?0:cur;
        //获得统计信息
        FileStoreStatistics statistics = myFileService.getCountStatistics(loginUser.getFileStoreId());
        //分页获得20个用户信息
        Page<Object> page = PageHelper.startPage(cur, 20);
        List<UserToShow> users = userService.getUsers();
        map.put("statistics", statistics);
        map.put("users", users);
        map.put("page", page);
        map.put("usersCount", usersCount);
        logger.info("用户管理域的内容:"+map);
        return "admin/manage-users";
    }

    /**
     * @Description 修改用户的权限和最大容量
     **/
    @GetMapping("/updateStoreInfo")
    @ResponseBody
    public String updateStoreInfo(Integer uId,Integer pre,Integer size){
        Integer integer = fileStoreService.updatePermission(uId, pre, size*1024);
        if (integer == 1) {
            //更新成功,返回200状态码
            logger.info("修改用户"+userService.queryById(uId).getUserName()+":的权限和仓库大小成功!");
            return "200";
        }else {
            //更新失败,返回500状态码
            logger.error("修改用户"+userService.queryById(uId).getUserName()+":的权限和仓库大小失败!");
            return "500";
        }
    }

    /**
     * @Description 删除用户
     **/
    @GetMapping("/deleteUser")
    public String deleteUser(Integer uId,Integer cur){
        cur = (cur == null || cur < 0)?1:cur;
        User user = userService.queryById(uId);
        FileStore fileStore = fileStoreService.getFileStoreByUserId(uId);
        List<FileFolder> folders = fileFolderService.getRootFoldersByFileStoreId(fileStore.getFileStoreId());
        //迭代删除文件夹
        for (FileFolder f:folders) {
            deleteFolderF(f);
        }
        List<MyFile> files = myFileService.getRootFilesByFileStoreId(fileStore.getFileStoreId());
        //删除该用户仓库根目录下的所有文件
        for (MyFile f:files) {
            String remotePath = f.getMyFilePath();
            String fileName = f.getMyFileName()+f.getPostfix();
            //从FTP文件服务器上删除文件
            boolean b = FtpUtil.deleteFile("/"+remotePath, fileName);
            if (b){
                //删除成功,返回空间
                fileStoreService.subSize(f.getFileStoreId(),Integer.valueOf(f.getSize()));
                //删除文件表对应的数据
                myFileService.deleteByFileId(f.getMyFileId());
            }
            logger.info("删除文件成功!"+f);
        }
        if (FtpUtil.deleteFolder("/" + uId)){
            logger.info("清空FTP上该用户的文件成功");
        }else {
            logger.error("清空FTP上该用户的文件失败");
        }
        userService.deleteById(uId);
        fileStoreService.deleteById(fileStore.getFileStoreId());
        return "redirect:/manages-users?cur="+cur;
    }

    /**
     * @Description 迭代删除文件夹里面的所有文件和子文件夹
     **/
    public void deleteFolderF(FileFolder folder){
        //获得当前文件夹下的所有子文件夹
        List<FileFolder> folders = fileFolderService.getFileFolderByParentFolderId(folder.getFileFolderId());
        //删除当前文件夹的所有的文件
        List<MyFile> files = myFileService.getFilesByParentFolderId(folder.getFileFolderId());
        if (files.size()!=0){
            for (int i = 0; i < files.size(); i++) {
                Integer fileId = files.get(i).getMyFileId();
                boolean b = FtpUtil.deleteFile("/"+files.get(i).getMyFilePath(), files.get(i).getMyFileName() + files.get(i).getPostfix());
                if (b){
                    myFileService.deleteByFileId(fileId);
                    fileStoreService.subSize(folder.getFileStoreId(),Integer.valueOf(files.get(i).getSize()));
                }
            }
        }
        if (folders.size()!=0){
            for (int i = 0; i < folders.size(); i++) {
                deleteFolderF(folders.get(i));
            }
        }
        fileFolderService.deleteFileFolderById(folder.getFileFolderId());
    }
}

文件仓库控制器:

/**
 * @ClassName: FileStoreController
 * @Description: 文件仓库控制器
 **/
@Controller
public class FileStoreController extends BaseController {
    private Logger logger = LogUtils.getInstance(FileStoreController.class);

    /**
     * @Description 上传临时文件
     **/
    @PostMapping("/uploadTempFile")
    public String uploadTempFile(@RequestParam("file") MultipartFile file,String url) {
        session.setAttribute("imgPath","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2654852821,3851565636&fm=26&gp=0.jpg");
        String name = file.getOriginalFilename().replaceAll(" ","");
        if (!checkTarget(name)){
            logger.error("临时文件上传失败!文件名不符合规范...");
            session.setAttribute("msg", "上传失败!文件名不符合规范");
            return "redirect:/temp-file";
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = format.format(new Date());
        String path = "temp/"+dateStr +"/"+UUID.randomUUID();
        try {
            if (FtpUtil.uploadFile("/"+path, name, file.getInputStream())){
                //上传成功
                logger.info("临时文件上传成功!"+name);
                String size = String.valueOf(file.getSize());
                TempFile tempFile = TempFile.builder().fileName(name).filePath(path).size(size).uploadTime(new Date()).build();
                if (tempFileService.insert(tempFile)) {
                    try {
                        String id = UUID.randomUUID().toString();
                        String p = request.getSession().getServletContext().getRealPath("/user_img/");
                        Long t = tempFile.getUploadTime().getTime();
                        url = url+"/file/share?t="+ UUID.randomUUID().toString().substring(0,10) +"&f="+tempFile.getFileId()+"&p="+size+"&flag=2";
                        File targetFile = new File(p, "");
                        if (!targetFile.exists()) {
                            targetFile.mkdirs();
                        }
                        File f = new File(p, id + ".jpg");
                        if (!f.exists()){
                            //文件不存在,开始生成二维码并保存文件
                            OutputStream os = new FileOutputStream(f);
                            QRCodeUtil.encode(url, "/static/img/logo.png", os, true);
                            os.close();
                        }
                        //异步删除临时文件
                        tempFileService.deleteById(tempFile.getFileId());
                        session.setAttribute("imgPath","user_img/"+id+".jpg");
                        session.setAttribute("url",url);
                        session.setAttribute("msg","上传成功,扫码/访问链接 即可下载!");
                        return "redirect:/temp-file";
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else {
                    logger.info("临时文件数据库写入失败!"+name);
                    session.setAttribute("url","error");
                    session.setAttribute("msg", "服务器出错了,临时文件上传失败!");
                }
            }else{
                //上传失败
                logger.info("临时文件上传失败!"+name);
                session.setAttribute("url","error");
                session.setAttribute("msg", "服务器出错了,上传失败!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:/temp-file";
    }

    /**
     * @Description 网盘的文件上传
     * @Author xw
     * @Date 23:10 2020/2/10
     * @Param [files]
     * @return java.util.Map<java.lang.String,java.lang.Object>
     **/
    @PostMapping("/uploadFile")
    @ResponseBody
    public Map<String, Object> uploadFile(@RequestParam("file") MultipartFile files) {
        Map<String, Object> map = new HashMap<>();
        if (fileStoreService.getFileStoreByUserId(loginUser.getUserId()).getPermission() != 0){
            logger.error("用户没有上传文件的权限!上传失败...");
            map.put("code", 499);
            return map;
        }
        FileStore store = fileStoreService.getFileStoreByUserId(loginUser.getUserId());
        Integer folderId = Integer.valueOf(request.getHeader("id"));
        String name = files.getOriginalFilename().replaceAll(" ","");
        //获取当前目录下的所有文件,用来判断是否已经存在
        List<MyFile> myFiles = null;
        if (folderId == 0){
            //当前目录为根目录
            myFiles = myFileService.getRootFilesByFileStoreId(loginUser.getFileStoreId());
        }else {
            //当前目录为其他目录
            myFiles = myFileService.getFilesByParentFolderId(folderId);
        }
        for (int i = 0; i < myFiles.size(); i++) {
            if ((myFiles.get(i).getMyFileName()+myFiles.get(i).getPostfix()).equals(name)){
                logger.error("当前文件已存在!上传失败...");
                map.put("code", 501);
                return map;
            }
        }
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = format.format(new Date());
        String path = loginUser.getUserId()+"/"+dateStr +"/"+folderId;
        if (!checkTarget(name)){
            logger.error("上传失败!文件名不符合规范...");
            map.put("code", 502);
            return map;
        }
        Integer sizeInt = Math.toIntExact(files.getSize() / 1024);
        //是否仓库放不下该文件
        if(store.getCurrentSize()+sizeInt > store.getMaxSize()){
            logger.error("上传失败!仓库已满。");
            map.put("code", 503);
            return map;
        }
        //处理文件大小
        String size = String.valueOf(files.getSize()/1024.0);
        int indexDot = size.lastIndexOf(".");
        size = size.substring(0,indexDot);
        int index = name.lastIndexOf(".");
        String tempName = name;
        String postfix = "";
        int type = 4;
        if (index!=-1){
            tempName = name.substring(index);
            name = name.substring(0,index);
            //获得文件类型
            type = getType(tempName.toLowerCase());
            postfix = tempName.toLowerCase();
        }
        try {
            //提交到FTP服务器
            boolean b = FtpUtil.uploadFile("/"+path, name + postfix, files.getInputStream());
            if (b){
                //上传成功
                logger.info("文件上传成功!"+files.getOriginalFilename());
                //向数据库文件表写入数据
                myFileService.addFileByFileStoreId(
                        MyFile.builder()
                              .myFileName(name).fileStoreId(loginUser.getFileStoreId()).myFilePath(path)
                              .downloadTime(0).uploadTime(new Date()).parentFolderId(folderId).
                              size(Integer.valueOf(size)).type(type).postfix(postfix).build());
                //更新仓库表的当前大小
                fileStoreService.addSize(store.getFileStoreId(),Integer.valueOf(size));
                try {
                    Thread.sleep(5000);
                    map.put("code", 200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                logger.error("文件上传失败!"+files.getOriginalFilename());
                map.put("code", 504);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * @Description 网盘的文件下载
     **/
    @GetMapping("/downloadFile")
    public String downloadFile(@RequestParam Integer fId){
        if (fileStoreService.getFileStoreByUserId(loginUser.getUserId()).getPermission() == 2){
            logger.error("用户没有下载文件的权限!下载失败...");
            return "redirect:/error401Page";
        }
        //获取文件信息
        MyFile myFile = myFileService.getFileByFileId(fId);
        String remotePath = myFile.getMyFilePath();
        String fileName = myFile.getMyFileName()+myFile.getPostfix();
        try {
            //去FTP上拉取
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("utf-8");
            // 设置返回类型
            response.setContentType("multipart/form-data");
            // 文件名转码一下,不然会出现中文乱码
            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            boolean flag = FtpUtil.downloadFile("/" + remotePath, fileName, os);
            if (flag) {
                myFileService.updateFile(
                        MyFile.builder().myFileId(myFile.getMyFileId()).downloadTime(myFile.getDownloadTime() + 1).build());
                os.flush();
                os.close();
                logger.info("文件下载成功!" + myFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "success";
    }

    /**
     * @Description 删除文件
     **/
    @GetMapping("/deleteFile")
    public String deleteFile(@RequestParam Integer fId,Integer folder){
        //获得文件信息
        MyFile myFile = myFileService.getFileByFileId(fId);
        String remotePath = myFile.getMyFilePath();
        String fileName = myFile.getMyFileName()+myFile.getPostfix();
        //从FTP文件服务器上删除文件
        boolean b = FtpUtil.deleteFile("/"+remotePath, fileName);
        if (b){
            //删除成功,返回空间
            fileStoreService.subSize(myFile.getFileStoreId(),Integer.valueOf(myFile.getSize()));
            //删除文件表对应的数据
            myFileService.deleteByFileId(fId);
        }
        logger.info("删除文件成功!"+myFile);
        return "redirect:/files?fId="+folder;
    }

    /**
     * @Description 删除文件夹并清空文件
     **/
    @GetMapping("/deleteFolder")
    public String deleteFolder(@RequestParam Integer fId){
        FileFolder folder = fileFolderService.getFileFolderByFileFolderId(fId);
        //强制删除
        deleteFolderF(folder);
        return folder.getParentFolderId() == 0?"redirect:/files":"redirect:/files?fId="+folder.getParentFolderId();
    } 

    /**
     * @Description 迭代删除文件夹里面的所有文件和子文件夹
     **/
    public void deleteFolderF(FileFolder folder){
        //获得当前文件夹下的所有子文件夹
        List<FileFolder> folders = fileFolderService.getFileFolderByParentFolderId(folder.getFileFolderId());
        //删除当前文件夹的所有的文件
        List<MyFile> files = myFileService.getFilesByParentFolderId(folder.getFileFolderId());
        if (files.size()!=0){
            for (int i = 0; i < files.size(); i++) {
                Integer fileId = files.get(i).getMyFileId();
                boolean b = FtpUtil.deleteFile("/"+files.get(i).getMyFilePath(), files.get(i).getMyFileName() + files.get(i).getPostfix());
                if (b){
                    myFileService.deleteByFileId(fileId);
                    fileStoreService.subSize(folder.getFileStoreId(),Integer.valueOf(files.get(i).getSize()));
                }
            }
        }
        if (folders.size()!=0){
            for (int i = 0; i < folders.size(); i++) {
                deleteFolderF(folders.get(i));
            }
        }
        fileFolderService.deleteFileFolderById(folder.getFileFolderId());
    }

    /**
     * @Description 添加文件夹
     **/
    @PostMapping("/addFolder")
    public String addFolder(FileFolder folder,Map<String, Object> map) {
        //设置文件夹信息
        folder.setFileStoreId(loginUser.getFileStoreId());
        folder.setTime(new Date());
        //获得当前目录下的所有文件夹,检查当前文件夹是否已经存在
        List<FileFolder> fileFolders = null;
        if (folder.getParentFolderId() == 0){
            //向用户根目录添加文件夹
            fileFolders = fileFolderService.getRootFoldersByFileStoreId(loginUser.getFileStoreId());
        }else{
            //向用户的其他目录添加文件夹
            fileFolders = fileFolderService.getFileFolderByParentFolderId(folder.getParentFolderId());
        }
        for (int i = 0; i < fileFolders.size(); i++) {
            FileFolder fileFolder = fileFolders.get(i);
            if (fileFolder.getFileFolderName().equals(folder.getFileFolderName())){
                logger.info("添加文件夹失败!文件夹已存在...");
                return "redirect:/files?error=1&fId="+folder.getParentFolderId();
            }
        }
        //向数据库写入数据
        Integer integer = fileFolderService.addFileFolder(folder);
        logger.info("添加文件夹成功!"+folder);
        return "redirect:/files?fId="+folder.getParentFolderId();
    }

    /**
     * @Description 重命名文件夹
     **/
    @PostMapping("/updateFolder")
    public String updateFolder(FileFolder folder,Map<String, Object> map) {
        //获得文件夹的数据库信息
        FileFolder fileFolder = fileFolderService.getFileFolderByFileFolderId(folder.getFileFolderId());
        fileFolder.setFileFolderName(folder.getFileFolderName());
        //获得当前目录下的所有文件夹,用于检查文件夹是否已经存在
        List<FileFolder> fileFolders = fileFolderService.getFileFolderByParentFolderId(fileFolder.getParentFolderId());
        for (int i = 0; i < fileFolders.size(); i++) {
            FileFolder folder1 = fileFolders.get(i);
            if (folder1.getFileFolderName().equals(folder.getFileFolderName()) && folder1.getFileFolderId() != folder.getFileFolderId()){
                logger.info("重命名文件夹失败!文件夹已存在...");
                return "redirect:/files?error=2&fId="+fileFolder.getParentFolderId();
            }
        }
        //向数据库写入数据
        Integer integer = fileFolderService.updateFileFolderById(fileFolder);
        logger.info("重命名文件夹成功!"+folder);
        return "redirect:/files?fId="+fileFolder.getParentFolderId();
    }

    /**
     * @Description 重命名文件
     **/
    @PostMapping("/updateFileName")
    public String updateFileName(MyFile file,Map<String, Object> map) {
        MyFile myFile = myFileService.getFileByFileId(file.getMyFileId());
        if (myFile != null){
            String oldName = myFile.getMyFileName();
            String newName = file.getMyFileName();
            if (!oldName.equals(newName)){
                boolean b = FtpUtil.reNameFile(myFile.getMyFilePath() + "/" + oldName+myFile.getPostfix(), myFile.getMyFilePath() + "/" + newName+myFile.getPostfix());
                if (b){
                    Integer integer = myFileService.updateFile(
                            MyFile.builder().myFileId(myFile.getMyFileId()).myFileName(newName).build());
                    if (integer == 1){
                        logger.info("修改文件名成功!原文件名:"+oldName+"  新文件名:"+newName);
                    }else{
                        logger.error("修改文件名失败!原文件名:"+oldName+"  新文件名:"+newName);
                    }
                }
            }
        }
        return "redirect:/files?fId="+myFile.getParentFolderId();
    }

    /**
     * @Description 获得二维码
     **/
    @GetMapping("getQrCode")
    @ResponseBody
    public Map<String,Object> getQrCode(@RequestParam Integer id,@RequestParam String url){
        Map<String,Object> map = new HashMap<>();
        map.put("imgPath","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2654852821,3851565636&fm=26&gp=0.jpg");
        if (id != null){
            MyFile file = myFileService.getFileByFileId(id);
            if (file != null){
                try {
                    String path = request.getSession().getServletContext().getRealPath("/user_img/");
                    url = url+"/file/share?t="+ UUID.randomUUID().toString().substring(0,10) +"&f="+file.getMyFileId()+"&p="+file.getUploadTime().getTime()+""+file.getSize()+"&flag=1";
                    File targetFile = new File(path, "");
                    if (!targetFile.exists()) {
                        targetFile.mkdirs();
                    }
                    File f = new File(path, id + ".jpg");
                    if (!f.exists()){
                        //文件不存在,开始生成二维码并保存文件
                        OutputStream os = new FileOutputStream(f);
                        QRCodeUtil.encode(url, "/static/img/logo.png", os, true);
                        os.close();
                    }
                    map.put("imgPath","user_img/"+id+".jpg");
                    map.put("url",url);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }

    /**
     * @Description 分享文件
     **/
    @GetMapping("/file/share")
    public String shareFile(Integer f,String p,String t,Integer flag){
        String fileNameTemp = "";
        String remotePath = "";
        String fileName = "";
        Integer times = 0;
        if (flag == null || f == null || p == null || t == null){
            logger.info("下载分享文件失败,参数错误");
            return "redirect:/error400Page";
        }
        if(flag == 1){
            //获取文件信息
            MyFile myFile = myFileService.getFileByFileId(f);
            if (myFile == null){
                return "redirect:/error404Page";
            }
            String pwd = myFile.getUploadTime().getTime()+""+myFile.getSize();
            if (!pwd.equals(p)){
                return "redirect:/error400Page";
            }
            remotePath = myFile.getMyFilePath();
            fileName = myFile.getMyFileName()+myFile.getPostfix();
        }else if(flag == 2){
            TempFile tempFile = tempFileService.queryById(f);
            if (tempFile == null){
                return "redirect:/error404Page";
            }
            Long test = tempFile.getUploadTime().getTime();

            String pwd = tempFile.getSize();
            if (!pwd.equals(p)){
                return "redirect:/error400Page";
            }
            remotePath = tempFile.getFilePath();
            fileName = tempFile.getFileName();
        }else {
            return "redirect:/error400Page";
        }
        fileNameTemp = fileName;
        try {
            //解决下载文件时 中文文件名乱码问题
            boolean isMSIE = isMSBrowser(request);
            if (isMSIE) {
                //IE浏览器的乱码问题解决
                fileNameTemp = URLEncoder.encode(fileNameTemp, "UTF-8");
            } else {
                //万能乱码问题解决
                fileNameTemp = new String(fileNameTemp.getBytes("UTF-8"), "ISO-8859-1");
            }
            //去FTP上拉取
            OutputStream os = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("utf-8");
            // 设置返回类型
            response.setContentType("multipart/form-data");
            // 文件名转码一下,不然会出现中文乱码
            response.setHeader("Content-Disposition", "attachment;fileName=" + fileNameTemp);
            if (FtpUtil.downloadFile("/" + remotePath, fileName, os)) {
                myFileService.updateFile(
                        MyFile.builder().myFileId(f).downloadTime(times + 1).build());
                os.flush();
                os.close();
                logger.info("文件下载成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "success";
    }

    /**
     * @Description 根据文件的后缀名获得对应的类型
     * @return int 1:文本类型   2:图像类型  3:视频类型  4:音乐类型  5:其他类型
     **/
    public int getType(String type){
        if (".chm".equals(type)||".txt".equals(type)||".xmind".equals(type)||".xlsx".equals(type)||".md".equals(type)
                ||".doc".equals(type)||".docx".equals(type)||".pptx".equals(type)
                ||".wps".equals(type)||".word".equals(type)||".html".equals(type)||".pdf".equals(type)){
            return  1;
        }else if (".bmp".equals(type)||".gif".equals(type)||".jpg".equals(type)||".ico".equals(type)||".vsd".equals(type)
                ||".pic".equals(type)||".png".equals(type)||".jepg".equals(type)||".jpeg".equals(type)||".webp".equals(type)
                ||".svg".equals(type)){
            return 2;
        } else if (".avi".equals(type)||".mov".equals(type)||".qt".equals(type)
                ||".asf".equals(type)||".rm".equals(type)||".navi".equals(type)||".wav".equals(type)
                ||".mp4".equals(type)||".mkv".equals(type)||".webm".equals(type)){
            return 3;
        } else if (".mp3".equals(type)||".wma".equals(type)){
            return 4;
        } else {
            return 5;
        }
    }

    /**
     * @Description 正则验证文件名是否合法 [汉字,字符,数字,下划线,英文句号,横线]
     **/
    public boolean checkTarget(String target) {
        final String format = "[^\\u4E00-\\u9FA5\\uF900-\\uFA2D\\w-_.]";
        Pattern pattern = Pattern.compile(format);
        Matcher matcher = pattern.matcher(target);
        return !matcher.find();
    }

    /**
     * @Description 判断当前浏览器是否为ie
     **/
    public static boolean isMSBrowser(HttpServletRequest request) {
        String[] IEBrowserSignals = {"MSIE", "Trident", "Edge"};
        String userAgent = request.getHeader("User-Agent");
        for (String signal : IEBrowserSignals) {
            if (userAgent.contains(signal)){
                return true;
            }
        }
        return false;
    }

}

登录控制器:

/**
 * @Description 登录控制器
 **/
@Controller
public class LoginController extends BaseController {

    private Logger logger = LogUtils.getInstance(LoginController.class);

    /**
     * @Description 免登陆用户入口,用于本地开发测试,上线运营为了安全请删除此方法
     * @Author xw
     * @Date 15:17 2020/2/26
     * @Param []
     * @return java.lang.String
     **/
    @GetMapping("/admin")
    public String adminLogin(){
        User user = userService.getUserByOpenId("123456");
        logger.info("使用免登陆方式登录成功!"+user);
        session.setAttribute("loginUser", user);
        return "redirect:/index";
    }

    /**
     * 用于注册流程,用户名,密码,邮箱等校验工作由前端来完成
     */
    @PostMapping("/register")
    public String register(User user, String code, Map<String, Object> map) {
        String uCode = (String) session.getAttribute(user.getEmail() + "_code");
        if (!code.equals(uCode)) {
            map.put("errorMsg", "验证码错误");
            return "index";
        }
        // 用户名去空格
        user.setUserName(user.getUserName().trim());
        user.setImagePath("https://p.qpic.cn/qqconnect/0/app_101851241_1582451550/100?max-age=2592000&t=0");
        user.setRegisterTime(new Date());
        user.setRole(1);
        if (userService.insert(user)) {
            FileStore store = FileStore.builder().userId(user.getUserId()).currentSize(0).build();
            fileStoreService.addFileStore(store);
            user.setFileStoreId(store.getFileStoreId());
            userService.update(user);
            logger.info("注册用户成功!当前注册用户" + user);
            logger.info("注册仓库成功!当前注册仓库" + store);
        } else {
            map.put("errorMsg", "服务器发生错误,注册失败");
            return "index";
        }
        session.removeAttribute(user.getEmail() + "_code");
        session.setAttribute("loginUser", user);
        return "redirect:/index";
    }

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public String login(User user, Map<String, Object> map) {
        User userByEmail = userService.getUserByEmail(user.getEmail());
        if (userByEmail != null && userByEmail.getPassword().equals(user.getPassword())) {
            session.setAttribute("loginUser", userByEmail);
            logger.info("登录成功!"+userByEmail);
            return "redirect:/index";
        }else{
            User user1 = userService.getUserByEmail(user.getEmail());
            String errorMsg = user1 == null ? "该邮箱尚未注册" : "密码错误";
            logger.info("登录失败!请确认邮箱和密码是否正确!");
            //登录失败,将失败信息返回前端渲染
            map.put("errorMsg", errorMsg);
            return "index";
        }
    }

    /**
     * @return void
     * @Description 向注册邮箱发送验证码, 并验证邮箱是否已使用
     **/
    @ResponseBody
    @RequestMapping("/sendCode")
    public String sendCode(String userName, String email, String password) {
        User userByEmail = userService.getUserByEmail(email);
        if (userByEmail != null) {
            logger.error("发送验证码失败!邮箱已被注册!");
            return "exitEmail";
        }
        logger.info("开始发送邮件.../n" + "获取的到邮件发送对象为:" + mailSender);
        mailUtils = new MailUtils(mailSender);
        String code = "123456";
        session.setAttribute(email + "_code", code);
        return "success";
    }

    /**
     * @Description 请求QQ登录
     **/
    @GetMapping("/loginByQQ")
    public void login() {
        response.setContentType("text/html;charset=utf-8");
        try {
            response.sendRedirect(new Oauth().getAuthorizeURL(request));
            logger.info("请求QQ登录,开始跳转...");
        } catch (QQConnectException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description QQ登录回调地址
     **/
    @GetMapping("/connection")
    public String connection() {
        try {
            AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);
            String accessToken = null, openID = null;
            long tokenExpireIn = 0L;
            if ("".equals(accessTokenObj.getAccessToken())) {
                logger.error("登录失败:没有获取到响应参数");
                return "accessTokenObj=>" + accessTokenObj + "; accessToken" + accessTokenObj.getAccessToken();
            } else {
                accessToken = accessTokenObj.getAccessToken();
                tokenExpireIn = accessTokenObj.getExpireIn();
                logger.error("accessToken" + accessToken);
                request.getSession().setAttribute("demo_access_token", accessToken);
                request.getSession().setAttribute("demo_token_expirein", String.valueOf(tokenExpireIn));
                // 利用获取到的accessToken 去获取当前用的openid -------- start
                OpenID openIDObj = new OpenID(accessToken);
                openID = openIDObj.getUserOpenID();
                UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);
                UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
                if (userInfoBean.getRet() == 0) {
                    logger.info("用户的OPEN_ID: " + openID);
                    logger.info("用户的昵称: " + removeNonBmpUnicode(userInfoBean.getNickname()));
                    logger.info("用户的头像URI: " + userInfoBean.getAvatar().getAvatarURL100());
                    //设置用户信息
                    User user = userService.getUserByOpenId(openID);
                    if (user == null){
                        user = User.builder()
                                .openId(openID).userName(removeNonBmpUnicode(userInfoBean.getNickname()))
                                .imagePath(userInfoBean.getAvatar().getAvatarURL100()).
                                registerTime(new Date()).build();
                        if (userService.insert(user)){
                            logger.info("注册用户成功!当前注册用户" + user);
                            FileStore store = FileStore.builder().userId(user.getUserId()).build();
                            if (fileStoreService.addFileStore(store) == 1){
                                user.setFileStoreId(store.getFileStoreId());
                                userService.update(user);
                                logger.info("注册仓库成功!当前注册仓库" + store);
                            }
                        } else {
                            logger.error("注册用户失败!");
                        }
                    }else {
                        user.setUserName(removeNonBmpUnicode(userInfoBean.getNickname()));
                        user.setImagePath(userInfoBean.getAvatar().getAvatarURL100());
                        userService.update(user);
                    }
                    logger.info("QQ用户登录成功!"+user);
                    session.setAttribute("loginUser", user);
                    return "redirect:/index";
                } else {
                    logger.error("很抱歉,我们没能正确获取到您的信息,原因是: " + userInfoBean.getMsg());
                }
            }
        } catch (QQConnectException e) {
        } finally {
            logger.error("登录成功!");
        }
        return "登录失败!请查看日志信息...";
    }

    /**
     * @Description 处理掉QQ网名中的特殊表情
     **/
    public String removeNonBmpUnicode(String str) {
        if (str == null) {
            return null;
        }
        str = str.replaceAll("[^\\u0000-\\uFFFF]", "");
        if ("".equals(str)) {
            str = "($ _ $)";
        }
        return str;
    }

    /**
     * @Description 退出登录,清空session
     **/
    @GetMapping("/logout")
    public String logout() {
        logger.info("用户退出登录!");
        session.invalidate();
        return "redirect:/";
    }

}

FTP工具类: 

/**
 * @ClassName: FtpUtil
 * @Description: FTP工具类
 **/
public class FtpUtil {
    /**
     * FTP服务器hostname
     */
    private static String HOST = "192.168.1.106";
    /**
     * FTP服务器端口
     */
    private static int PORT = 21;
    /**
     * FTP登录账号
     */
    private static String USERNAME = "chen";
    /**
     * FTP登录密码
     */
    private static String PASSWORD = "chenfuning";
    /**
     * FTP服务器基础目录
     */
    private static String BASEPATH = "";
    /**
     * FTP客户端
     */
    private static FTPClient ftp;

    /**
     * @Description 初始化FTP客户端
     **/
    public static boolean initFtpClient(){
        ftp = new FTPClient();
        int reply;
        try {
            // 连接FTP服务器
            ftp.connect(HOST, PORT);
            //登录, 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
            ftp.login(USERNAME, PASSWORD);
            ftp.setBufferSize(10240);
            //设置传输超时时间为60秒
            ftp.setDataTimeout(600000);
            //连接超时为60秒
            ftp.setConnectTimeout(600000);
            //FTP以二进制形式传输
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * Description: 向FTP服务器上传文件
     * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath
     * @param filename 上传到FTP服务器上的文件名
     * @param input 本地要上传的文件的 输入流
     * @return 成功返回true,否则返回false
     */
    public static boolean uploadFile(String filePath, String filename, InputStream input) {
        boolean result = false;
        try {
            filePath = new String(filePath.getBytes("GBK"),"iso-8859-1");
            filename = new String(filename.getBytes("GBK"),"iso-8859-1");
             if (!initFtpClient()){
                 return result;
             };
            //切换到上传目录
            ftp.enterLocalPassiveMode();
            if (!ftp.changeWorkingDirectory(BASEPATH+filePath)) {
                //如果目录不存在创建目录
                String[] dirs = filePath.split("/");
                String tempPath = BASEPATH;
                for (String dir : dirs) {
                    if (null == dir || "".equals(dir)){
                        continue;
                    }
                    tempPath += "/" + dir;
                    if (!ftp.changeWorkingDirectory(tempPath)) {
                        if (!ftp.makeDirectory(tempPath)) {
                            return result;
                        } else {
                            ftp.changeWorkingDirectory(tempPath);
                        }
                    }
                }
            }
            //设置上传文件的类型为二进制类型
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            //上传文件
            ftp.enterLocalPassiveMode();
            if (!ftp.storeFile(filename, input)) {
                return result;
            }
            input.close();
            ftp.logout();
            result = true;
        }
        catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    /**
     * Description: 从FTP服务器下载文件
     * @param remotePath FTP服务器上的相对路径
     * @param fileName 要下载的文件名
     * @return
     */
    public static boolean downloadFile( String remotePath,String fileName,String localPath) {
        boolean result = false;

        try {
            remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
            fileName = new String(fileName.getBytes("GBK"),"iso-8859-1");
            if (!initFtpClient()){
                return result;
            };
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            ftp.enterLocalPassiveMode();
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    ftp.enterLocalPassiveMode();
                    FileOutputStream outputStream = new FileOutputStream(new File(localPath));
                    ftp.retrieveFile(remotePath+"/"+fileName,outputStream);

                    result = true;
                    outputStream.close();
                }
            }
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    /**
     * @Description 从ftp服务器下载文件到指定输出流
     * @Param [remotePath, fileName, outputStream]
     * @return boolean
     **/
    public static boolean downloadFile(String remotePath, String fileName, OutputStream outputStream) {
        boolean result = false;
        try {
            remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
            fileName = new String(fileName.getBytes("GBK"),"iso-8859-1");
            if (!initFtpClient()){
                return result;
            };
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            ftp.enterLocalPassiveMode();
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if (ff.getName().equals(fileName)) {
                    ftp.enterLocalPassiveMode();
                    ftp.retrieveFile(remotePath+"/"+fileName,outputStream);
                    result = true;
                }
            }
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    /**
     * @Description 删除文件
     * @Param [remotePath, fileName]
     * @return void
     **/
    public static boolean deleteFile( String remotePath,String fileName){
        boolean flag = false;
        try {
            remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
            fileName = new String(fileName.getBytes("GBK"),"iso-8859-1");
            if (!initFtpClient()){
                return flag;
            };
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            ftp.enterLocalPassiveMode();
            FTPFile[] fs = ftp.listFiles();
            for (FTPFile ff : fs) {
                if ("".equals(fileName)){
                    return flag;
                }
                if (ff.getName().equals(fileName)){
                    String filePath = remotePath + "/" +fileName;
                    ftp.deleteFile(filePath);
                    flag = true;
                }
            }
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return flag;
    }

    /**
     * @Description 删除文件夹
     * @Param [remotePath, fileName]
     * @return void
     **/
    public static boolean deleteFolder( String remotePath){
        boolean flag = false;
        try {
            remotePath = new String(remotePath.getBytes("GBK"),"iso-8859-1");
            if (!initFtpClient()){
                return flag;
            };
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remotePath);
            ftp.enterLocalPassiveMode();
            FTPFile[] fs = ftp.listFiles();
            if (fs.length==0){
                ftp.removeDirectory(remotePath);
                flag = true;
            }
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return flag;
    }

    /**
     * @Description 修改文件名称或者文件夹名
     * @Param [oldAllName, newAllName]
     * @return boolean
     **/
    public static boolean reNameFile( String oldAllName,String newAllName){
        boolean flag = false;
        try {
            oldAllName = new String(oldAllName.getBytes("GBK"),"iso-8859-1");
            newAllName = new String(newAllName.getBytes("GBK"),"iso-8859-1");
            if (!initFtpClient()){
                return flag;
            };
            ftp.enterLocalPassiveMode();
            ftp.rename(oldAllName,newAllName);
            flag = true;
            ftp.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return flag;
    }
}

以上就是Java+Springboot搭建一个在线网盘文件分享系统的详细内容,更多关于Java Springboot 的资料请关注我们其它相关文章!

(0)

相关推荐

  • 基于java ssm springboot+mybatis酒庄内部管理系统设计和实现

    目录 咱们废话不多说进入主题.系统主页展示: 用户信息管理; 角色权限控制管理: 管理员查看灵活配置; 插入一小部分代码段 通知公告信息管理 总结 咱们废话不多说进入主题.系统主页展示: 用户登录后进行系统首页:主要功能模块如下.分角色管理.超级管理员拥有最高权限.可以进行菜单灵活控制. 用户信息管理; 角色权限控制管理: 管理员查看灵活配置; 插入一小部分代码段 /** * . * * * * */ package io.renren.modules.sys.controller; impor

  • 选课推荐交流平台系统基于java ssm springboot实现

    目录 主要功能模块设计: 主要技术: 主要功能实现前端: 选课平台首页: 登录注册管理: 选课推荐分类: 课程详情信息: 我的个人中心: 主要功能实现后台: 系统主页设计: 选课类型管理: 选课信息详情管理: 通知公告信息: 用户信息管理: 评论交流回复管理: 部分关键代码展示: 登录模块: 配置模块: 主要表设计: 用户表: 选课类型表: 选课详情表: 评论交流表: 回复信息表: 夏天到了.小雪来给大家降降温 话不多说.直接进入主题 主要功能模块设计: 登录注册.首页信息浏览.选课分类查看.选

  • 基于java SSM springboot实现景区行李寄存管理系统

    主要技术实现设计:spring. springmvc. springboot. springboot security权限控制.mybatis .session. jquery . md5 .bootstarp.js tomcat.拦截器等. 主要功能实现设计:登录.用户管理.角色权限管理.菜单管理.部门管理.行李柜管理.用户寄存管理.记录查询管理.通知公告管理.入柜.出柜以及修改密码等操作. 项目介绍 随着中国人对于旅游休闲的积极认识和市场的需求不断增加,各个景区为了满足游客需求也在不断的开发

  • 基于java SSM springboot实现抗疫物质信息管理系统

    主要功能设计: 用户.区域.物质类型.物质详情.物质申请和审核以及我的申请和通知公告以及灵活控制菜单权限 主要技术实现:spring. springmvc. springboot.springboot security权限框架 mybatis . jquery . md5 .bootstarp.js tomcat.器.拦截器等 具体功能模块:用户模块.角色模块.菜单模块.部门模块以及灵活的权限控制,可控制到页面或按钮,满足绝大部分的权限需求 业务模块功能:区域管理.对不同区域的进行管理以及物质发

  • 基于Java SpringBoot的前后端分离信息管理系统的设计和实现

    目录 前言 视频演示 主要功能说明 功能截图 主要代码实现 主要数据表设计 前言 当今社会,随着科学技术的发展,以及市场经济的多元化,使人才的流动速度大大增加,因此也对党建工作的管理层面工作带来了空前且复杂的挑战, 从而使得如何高效的开展管理党建工作成为了亟待解决的问题.为此将高速发展的信息科学技术引入到党建工作管理的应用中,力求合理有效的提升全面各项工作的进展,实现以人为本的科学发展思想和意识,是一种高效可实现的方法. Java作为一种面向对象的.可以撰写跨平台应用软件的程序设计语言,其技术具

  • Java+Springboot搭建一个在线网盘文件分享系统

    目录 前言 效果图 主要代码 管理员控制器: 文件仓库控制器: 登录控制器: FTP工具类:  前言 springboot+freemark+jpa+MySQL实现的在线网盘文件分享系统,其功能跟百度网盘非常类似,普通用户可以注册登录,注册后默认分配1G的空间大小,登录进去后可以新建文件夹.上传各种类型的文件.文件移动.复制.下载.删除.分享,分享分为私密分享和公开分享,还可以设置分享过期时间,打开分享链接后可以对文件进行查看.下载.保存到自己网盘等.超级管理员登录后可以设置普通用户的空间大小.

  • Java如何搭建一个个人网盘

    目录 前言 一.项目介绍 二.网盘搭建 2.1 Windows 环境运行 2.2 Linux 环境运行 三.开发环境运行 3.1 下载项目 3.2 运行 3.3 阅读代码 四.功能说明 4.1 上传 4.2 视频/音频播放 4.3 快捷键使用 4.4 配置文件修改 4.5 在线预览 4.6 分享下载链接 五.最后 前言 本文适合有 Java 基础知识的人群,跟着本文可学习和运行 Java 网盘项目. 今天给大家带来一款开源 Java 版网盘项目-- kiftd-source,本文将用 3 分钟带

  • Java毕业设计实战之在线网盘系统的实现

    一.项目简述 功能:用户的邮箱注册.验证码验证以及用户登录. 不需要注册账号,也可以上传满足条件的临时文件,但是只4小时内有效. 文件的管理,上传.下载.重命名.删除.查看统计数据.分类管理等. 文件夹的管理,创建.删除.重命名. 文件的分享,支持通过链接和二维码的分享方式等等,以及管理员对用户的管理等等. 二.项目运行 环境配置: Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持) 项目技术:

  • Django实现文件分享系统的完整代码

    一.效果展示 文件上传和展示: 文件搜索: 文件下载: 删除文件: 二.关键代码 #urls.py from django.urls import path,re_path from .views import HomeView,DisplayView,MyView,SearchView from . import views app_name = 'share' urlpatterns = [ path('', HomeView.as_view(), name='home'), # 当用户发起

  • 10分钟用python搭建一个超好用的CMDB系统

    CMDB 是什么,作为 IT 工程师的你想必已经听说过了,或者已经烂熟了,容我再介绍一下,以防有读者还不知道.CMDB 的全称是 Configuration Management Data Base,翻译下就是配置管理数据库,它存储与管理企业 IT 架构中设备的各种配置信息,它支撑服务流程的运转.发挥着配置信息的价值.在今天,无论是自动化运维.标准化运维.DevOps.甚至是时髦的智能运维,其实都离开不 CMDB,可以说 CMDB 是运维体系的基石,有了配置信息数据库,后面各种标准.流程都可以建

  • 用Pelican搭建一个极简静态博客系统过程解析

    我一直建议每个开发者都要有写博客记笔记的习惯,一来可以沉淀知识,二来可以帮助别人,我使用过很多博客平台,也用Python开发过博客系统,就这么个东西折腾好几年,一直找不到理想的产品,直到我用Pelican之前. Pelican 是基于Python实现的开源静态博客系统,所谓静态博客系统就是无需数据库,每一篇文章会事先渲染成HTML静态文件,访问速度非常快.所以今天给大家介绍下怎么使用Pelican. 使用Pelican 你需要了解一点git,熟悉基本的Linux shell 命令,懂一点Pyth

  • 从零开始搭建一个react项目开发

    本文介绍了从零开始搭建一个react项目开发,分享给大家,具体如下: 1.npm init 生成 package.json 文件. 2.安装各种需要的依赖: npm install  --save react - 安装React. npm install  --save react-dom 安装React Dom,这个包是用来处理virtual DOM.这里提一下用React Native的话,这里就是安装react-native. npm install  --save-dev webpack

  • IDEA上面搭建一个SpringBoot的web-mvc项目遇到的问题

    这几天一直在研究IDEA上面怎么搭建一个web-mvc的SpringBoot项目,看网上的教程一步步的搭建,可是还是出现一堆的问题. 为了让大家以后少走一些弯路,我在这里分享一下我这几天研究的成果,也希望对大家能有所帮助. 这里先介绍一下各种环境的配置信息:idea2016.2.1  jdk1.8.0_31 因为SpringBoot中是内置tomcat的,所以也就不需要额外的tomcat配置了,现在开始讲如何在idea上面搭建SpringBoot web-mvc项目了 步骤一:在IDEA中新建一

  • SpringBoot之Helloword 快速搭建一个web项目(图文)

    背景: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者. Spring Boot(英文中是"引导"的意思),是用来简化Spring应用的搭建到开发的过程.应用开箱即用,只要通过 "just

  • 使用IDEA搭建一个简单的SpringBoot项目超详细过程

    一.创建项目 1.File->new->project: 2.选择"Spring Initializr",点击next:(jdk1.8默认即可) 3.完善项目信息,组名可不做修改,项目名可做修改:最终建的项目名为:test,src->main->java下包名会是:com->example->test:点击next: 4.Web下勾选Spring Web Start,(网上创建springboot项目多是勾选Web选项,而较高版本的Springboo

随机推荐