手把手教你设计一个CSDN系统

简介: 在CSDN发一个CSDN系统是什么体验?大家都知道CSDN 有一个下载的模块,就是用户上传资源然后管理员会进行审核,上传资源的用户可以赚钱还可以赚积分。

在CSDN发一个CSDN系统是什么体验?


大家都知道CSDN 有一个下载的模块,就是用户上传资源然后管理员会进行审核,上传资源的用户可以赚钱还可以赚积分。


微信图片_20221009224734.png

那么个人可不可以开发这样的系统呢?


完全可以!


小孟前面就就可开发了一个,而且处理很详细的教程。具体的介绍如下所示:


一,技术简介


该项目非常详细的讲解了springboot,可以用于面试、毕设、学习等。

最新版的springboot2.0框架;


前端框架采用流行的Layui;


redis高性能缓存框架,存放热门数据,常用数据;


thymeleaf模版引擎;


shiro安全框架;


javamail集成,找回密码用到;


数据库连接池使用的是阿里巴巴的Druid;


全文检索lucene;


QQ第三方登录。


微信图片_20221009224744.png


二,系统演示


微信图片_20221009224750.png


微信图片_20221009224756.png


微信图片_20221009224800.png


微信图片_20221009224806.png


微信图片_20221009224811.png


微信图片_20221009224816.png


微信图片_20221009224820.png


微信图片_20221009224825.png


系统不管是界面还是功能都非常的nice,如果想看详细的教程或者演示,也有对系统的本系统的学习


https://www.bilibili.com/video/BV1jJ41197BJ?p=110&vd_source=e64f225fc5daf048d2687502cb23bb3b


三,核心代码展示


/**
 * 小孟V:jishulearn
 */
@RestController
@RequestMapping(value = "/article")
public class ArticleController {
    @Autowired
    private ArcTypeService arcTypeService;
    @Autowired
    private ArticleService articleService;
    @Autowired
    private ArticleIndex articleIndex;
    /**
     * 按资源类型分页查询资源列表
     * @param type
     * @param currentPage
     * @return
     */
    @RequestMapping("/{type}/{currentPage}")
    public ModelAndView type(@PathVariable(value = "type",required = false) String type, @PathVariable(value = "currentPage",required = false)Integer currentPage){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("index");
        //类型的html代码
        List arcTypleList = arcTypeService.listAll(Sort.Direction.ASC,"sort");
        mav.addObject("arcTypeStr", HTMLUtil.getArcTypeStr(type,arcTypleList));
        //资源列表
        Map<String,Object> map = articleService.list(type,currentPage, Consts.PAGE_SIZE);
        mav.addObject("articleList",map.get("data"));
        //分页html代码
        mav.addObject("pageStr",HTMLUtil.getPagation("/article/"+type,Integer.parseInt(String.valueOf(map.get("count"))),currentPage,"该分类还没有数据..."));
        return mav;
    }
    /**
     * 关键字分词搜索
     */
    @RequestMapping("/search")
    public ModelAndView search(String keywords,@RequestParam(value = "page",required = false) Integer page) throws ParseException, InvalidTokenOffsetsException, org.apache.lucene.queryparser.classic.ParseException, IOException {
        if(page==null){
            page = 1;
        }
        ModelAndView mav = new ModelAndView();
        mav.setViewName("index");
        //类型的html代码
        List arcTypleList = arcTypeService.listAll(Sort.Direction.ASC,"sort");
        mav.addObject("arcTypeStr", HTMLUtil.getArcTypeStr("all",arcTypleList));
        //资源列表
        List<Article> articleList = articleIndex.search(keywords);
        Integer toIndex = articleList.size()>=page*Consts.PAGE_SIZE?page*Consts.PAGE_SIZE:articleList.size();
        mav.addObject("articleList",articleList.subList((page-1)*Consts.PAGE_SIZE,toIndex));
        mav.addObject("keywords",keywords);
        //分页html代码
        int totalPage = articleList.size()%Consts.PAGE_SIZE==0?articleList.size()/Consts.PAGE_SIZE:articleList.size()/Consts.PAGE_SIZE+1;
        String targetUrl = "/article/search?keywords="+keywords;
        String msg = "没有关键字是 \"<font style=\"border: 0px;color:red;font-weight:bold;padding-left: 3px; padding-right: 3px;\" >" +keywords + "</font>\" 的相关资源,请联系站长!";
        mav.addObject("pageStr",HTMLUtil.getPagation2(targetUrl,totalPage,page,msg));
        return mav;
    }
    /**
     * 资源详情
     */
    @RequestMapping("/detail/{articleId}")
    public ModelAndView detail(@PathVariable(value = "articleId",required = false) String articleId) throws IOException, org.apache.lucene.queryparser.classic.ParseException {
        ModelAndView mav = new ModelAndView();
        String replace = articleId.replace(".html","");
        articleService.updateClick(Integer.parseInt(replace));
        Article article = articleService.getById(Integer.parseInt(replace));
        if(article.getState()!=2){
            return null;
        }
        mav.addObject("article",article);
        //类型的html代码
        List arcTypleList = arcTypeService.listAll(Sort.Direction.ASC,"sort");
        mav.addObject("arcTypeStr", HTMLUtil.getArcTypeStr(article.getArcType().getArcTypeId().toString(),arcTypleList));
        //通过lucene分词查找相似资源
        List<Article> articleList = articleIndex.searchNoHighLighter(article.getName().replace("视频","").replace("教程","")
                            .replace("下载","").replace("PDF",""));
        if(articleList!=null&&articleList.size()>0){
            mav.addObject("similarityArticleList",articleList);
        }
        mav.setViewName("detail");
        return mav;
    }
    /**
     * 判断资源是否免费
     */
    @ResponseBody
    @RequestMapping("/isFree")
    public boolean isFree(Integer articleId){
        Article article = articleService.getById(articleId);
        return article.isFree();
    }
}



/**
 * 小孟V:jishulearn
 */
@Controller
@RequestMapping(value = "/comment")
public class CommentController {
    @Autowired
    private CommentService commentService;
    /**
     * 前端提交保存评论信息
     * @param comment
     * @param session
     * @return
     */
    @ResponseBody
    @PostMapping("/add")
    public Map<String,Object> add(Comment comment, HttpSession session){
        Map<String,Object> map = new HashMap<>();
        comment.setContent(StringUtil.esc(comment.getContent()));
        comment.setCommentDate(new Date());
        comment.setState(0);
        comment.setUser((User)session.getAttribute(Consts.CURRENT_USER));
        commentService.save(comment);
        map.put("success",true);
        return map;
    }
    /**
     * 分页查询某个资源的评论信息
     */
    @ResponseBody
    @RequestMapping(value = "/list")
    public Map<String,Object> list(Comment s_comment, @RequestParam(value = "page",required = false)Integer page){
        s_comment.setState(1);
        Page<Comment> commentPage = commentService.list(s_comment,page,5, Sort.Direction.DESC,"commentDate");
        Map<String,Object> map = new HashMap<>();
        map.put("data", HTMLUtil.getCommentPageStr(commentPage.getContent()));          //评论的HTML代码
        map.put("total",commentPage.getTotalPages());                                   //总页数
        return map;
    }
}


/**
 * 根路径及其他请求处理
 */
@Controller
public class IndexController {
    @Autowired
    private ArcTypeService arcTypeService;
    @Autowired
    private ArticleService articleService;
    @Autowired
    private UserService userService;
    @Autowired
    private MessageService messageService;
    @Value("${imgFilePath}")
    private String imgFilePath;         //图片上传路径
    /**
     * 首页
     */
    @RequestMapping("/")
    public ModelAndView index(){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("index");
        //类型的html代码
        List arcTypleList = arcTypeService.listAll(Sort.Direction.ASC,"sort");
        mav.addObject("arcTypeStr", HTMLUtil.getArcTypeStr("all",arcTypleList));
        //资源列表
        Map<String,Object> map = articleService.list("all",1, Consts.PAGE_SIZE);
        mav.addObject("articleList",map.get("data"));
        //分页html代码
        mav.addObject("pageStr",HTMLUtil.getPagation("/article/all",Integer.parseInt(String.valueOf(map.get("count"))),1,"该分类还没有数据..."));
        return mav;
    }
    /**
     * QQ登录回调
     */
    @RequestMapping("/connect")
    public String qqCallback(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws QQConnectException {
        response.setContentType("text/html;charset=utf-8");
        AccessToken accessTokenObj = new Oauth().getAccessTokenByRequest(request);
        String accessToken = null;
        String openId = null;
        String state = request.getParameter("state");
        String session_state = (String) session.getAttribute("qq_connect_state");
        if(StringUtil.isEmpty(session_state)||!session_state.equals(state)){
            System.out.println("非法请求");
            return "redirect:/";
        }
        accessToken = accessTokenObj.getAccessToken();
        if(StringUtil.isEmpty(accessToken)){
            System.out.println("没有获取到响应参数");
            return "redirect:/";
        }
        session.setAttribute("accessToken",accessToken);
        OpenID openIDObj = new OpenID(accessToken);
        openId = openIDObj.getUserOpenID();
        UserInfo qzoneUserInfo = new UserInfo(accessToken,openId);
        UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
        if(userInfoBean==null||userInfoBean.getRet()!=0||StringUtil.isNotEmpty(userInfoBean.getMsg())){
            System.out.println("没有对应的qq信息");
            return "redirect:/";
        }
        //获取用户成功
        User currentUser = (User)session.getAttribute(Consts.CURRENT_USER);
        if(currentUser!=null&&StringUtil.isNotEmpty(currentUser.getUserName())&&StringUtil.isNotEmpty(currentUser.getEmail())&&StringUtil.isEmpty(currentUser.getOpenId())){
            currentUser.setOpenId(openId);
            userService.save(currentUser);
            session.setAttribute(Consts.CURRENT_USER,currentUser);
            return "redirect:/";
        }
        User user = userService.findByOpenId(openId);
        if(user==null){             //该用户是第一次登录,先注册
            user = new User();
            user.setOpenId(openId);
            user.setNickname(userInfoBean.getNickname());
            String imgName = DateUtil.getCurrentDateStr()+".jpg";
            downloadPicture(userInfoBean.getAvatar().getAvatarURL100(),imgFilePath+imgName);
            user.setHeadPortrait(imgName);
            user.setSex(userInfoBean.getGender());
            user.setPassword(CryptographyUtil.md5("123456",CryptographyUtil.SALT));
            user.setRegistrationDate(new Date());
            user.setLatelyLoginTime(new Date());
            //userService.save(user);
            session.setAttribute(Consts.CURRENT_USER,user);
        }else{                  //已经注册过,更新用户信息,直接将信息存入session 然后跳转
            if(!user.isOff()){     //非封号状态
                user.setNickname(userInfoBean.getNickname());
                user.setSex(userInfoBean.getGender());
                user.setLatelyLoginTime(new Date());
                userService.save(user);
                Subject subject = SecurityUtils.getSubject();
                UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword());
                subject.login(token);               //登录验证
                Integer messageCount = messageService.getCountByUserId(user.getUserId());
                user.setMessageCount(messageCount);
                Article s_article = new Article();
                s_article.setUseful(false);
                s_article.setUser(user);
                session.setAttribute(Consts.UN_USEFUL_ARTICLE_COUNT,articleService.getCount(s_article,null,null,null));
                session.setAttribute(Consts.CURRENT_USER,user);
            }
        }
        return "redirect:/";
    }
    /**
     * 通过链接下载图片保存到头像文件夹
     */
    private void downloadPicture(String urlString,String path){
        URL url = null;
        DataInputStream dataInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            url = new URL(urlString);
            dataInputStream = new DataInputStream(url.openStream());
            fileOutputStream = new FileOutputStream(new File(path));
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = dataInputStream.read(buffer))>0){
                output.write(buffer,0,length);
            }
            fileOutputStream.write(output.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                dataInputStream.close();
                fileOutputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
目录
相关文章
|
3月前
|
人工智能 前端开发 机器人
【杂谈】扣子(Coze) 初体验
扣子(Coze)是什么 官方原文如下: 扣子(coze.cn)是一款用来开发新一代 AI Chat Bot 的应用编辑平台,无论你是否有编程基础,都可以通过这个平台来快速创建各种类型的 Chat Bot,并将其发布到各类社交平台和通讯软件上。 我们可以理解为一个聊天🤖️,可以在其他平台上发布。那就让我们快速开始吧
354 0
|
5月前
|
算法 机器人 C++
C++零基础全面教程(开篇介绍)
C++零基础全面教程(开篇介绍)
35 0
|
8月前
|
程序员
在技术社区编写技术博客的一些心得体会
在技术社区编写技术博客的一些心得体会
20 0
|
9月前
|
前端开发 程序员 数据库
程序员需要知道的50个网址,包括编程社区、开发工具、技术博客、在线课程等。
以下是 50 个程序员必须要知道的网站: 1. Codecademy(www.codecademy.com):在线编程学习平台,提供多种编程语言的入门课程。 2. Khan Academy(www.khanacademy.org):非营利性在线学习平台,提供有关计算机科学和编程的免费课程。 3. Udemy(www.udemy.com):在线教育平台,提供大量编程课程,包括入门课程和进阶课程。 4. Coursera(www.coursera.org):在线教育平台,提供全球顶尖大学和机构的编程课程。 5. edX(www.edx.org):在线教育平台,提供全球顶尖大学和机构的编程课程。 6
|
机器学习/深度学习 人工智能 算法
我的第一篇博客--C++课程设计
前言 这是我的第一篇博客,内容便是最近所做的课程设计,之后也会每天和大家分享一下刷题笔记,以及AC后的代码,希望大家的批评指正,分享大家的一些观点和想法,希望和大家共同进步。
71 0
|
自然语言处理 JavaScript 前端开发
|
JSON 小程序 JavaScript
全栈工程师之路-中级篇之小程序开发-第一章第三节阅读官方demo
全栈工程师之路-中级篇之小程序开发-第一章第三节阅读官方demo
152 0
全栈工程师之路-中级篇之小程序开发-第一章第三节阅读官方demo
|
缓存 JavaScript 前端开发
手把手教你从0开始搭建个人博客,东半球最详细的保姆级博客搭建部署教程 | 程序员人手必备个人博客网站
手把手教你从0开始搭建个人博客,东半球最详细的保姆级博客搭建部署教程 | 程序员人手必备个人博客网站
手把手教你从0开始搭建个人博客,东半球最详细的保姆级博客搭建部署教程 | 程序员人手必备个人博客网站
|
Web App开发 JavaScript 前端开发