[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".gitignore",
    "content": "\n# crawler/.idea/*\n# crawler/__pycache__/*\n# crawler/database-properties.json\n.DS_Store\n\n/back/lib/*.jar\nback/src/main/resources/application.properties\n\n*.pyc\nspider/log/*.txt\nspider/.idea/*\nspider/experiment/*\nspider/properties/database.json\nspider/debug.log\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 SmacUL\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "NewsRecommend.sql",
    "content": "DROP DATABASE IF EXISTS NR;\nCREATE DATABASE IF NOT EXISTS NR CHARACTER SET utf8mb4;\n\n\n-- cus 用户\nDROP TABLE IF EXISTS NR.Customer;\nCREATE TABLE NR.Customer (\n    cus_id INT UNSIGNED NOT NULL auto_increment,\n    cus_name VARCHAR(64) UNIQUE,\n    cus_pass VARCHAR(255),\n    -- 爬虫中用于识别用户\n    cus_spider VARCHAR(64) default '',\n    -- 用户头像的 url\n    cus_avatar_url VARCHAR(255) default 'http://localhost:8080/img/Man.png',\n    -- 用户的个人描述\n    cus_style VARCHAR(255) default '这个人很懒, 什么都没写',\n    -- cus_gender 为 0 时性别未知, 为 1 时为男, 为 -1 时为女\n    cus_gender TINYINT DEFAULT 0,\n    -- 用户的创建时间\n    cus_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    -- cus_legal 为 0 时待审核, 为 1 时合法, 为 -1 不合法\n    cus_legal TINYINT default 0,\n\n    -- cus_type 为 0 时是普通用户, 为 1 时是可编辑用户 ABANDON\n    -- cus_type TINYINT default 0,\n    -- 用户背景墙的图片 url ABANDON\n    -- cus_background_url VARCHAR(255) default '',\n    -- 此用户的关注的用户数量 ABANDON\n    -- cus_follow_num int UNSIGNED default 0,\n    -- 此用户的粉丝 ABANDON\n    -- cus_fan_num int UNSIGNED default 0, \n    -- 此用户的文章数量 ABANDON\n    -- cus_article_num int UNSIGNED default 0,\n    -- 用户评分 ABANDON\n    -- cus_scope int UNSIGNED default 0,\n\t\n    primary key(cus_id)\n);\n\n\n-- art 新闻\nDROP TABLE IF EXISTS NR.Article;\nCREATE TABLE NR.Article (\n    art_id INT UNSIGNED NOT NULL auto_increment,\n    art_title VARCHAR(255) default '',\n    art_content TEXT,\n    -- 在爬虫中分辨文章\n    art_spider VARCHAR(64) default '',\n    -- 文章的分类\n    art_type VARCHAR(32),\n    -- 文章的标签 应该以 & 分隔\n    art_tags VARCHAR(128) default '',\n    -- 文章缩略图的信息\n    art_image_url VARCHAR(255) default '',\n    art_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    art_legal tinyint default 0,\n    art_cus_id INT UNSIGNED,\n\n    -- 文章的点赞数量 ABANDON\n    -- art_like_num INT UNSIGNED default 0,\n    -- 文章的点踩数量 ABANDON\n    -- art_dislike_num INT UNSIGNED default 0,\n    -- 文章的评论数量 ABANDON\n    -- art_comment_num INT UNSIGNED default 0,\n    -- 文章的分数 ABANDON\n\t-- art_scope int UNSIGNED default 0,\n    \n    primary key(art_id),\n\tforeign key(art_cus_id) references Customer(cus_id)\n);\n\n\n-- com 评论 \nDROP TABLE IF EXISTS NR.Comment;\nCREATE TABLE NR.Comment (\n    com_id INT UNSIGNED NOT NULL auto_increment,\n    com_content TEXT,\n    com_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    com_legal tinyint default 0,\n    -- 爬虫过程中的评论标识\n    com_spider varchar(64) default '',\n    com_cus_id INT UNSIGNED,\n    com_art_id INT UNSIGNED, \n\n    -- ABANDON\n    -- com_like_num INT UNSIGNED default 0,\n    -- ABANDON\n    -- com_dislike_num INT UNSIGNED default 0,\n\t-- 评论的回复数量 ABANDON\n    -- com_reply_num INT UNSIGNED default 0,\n    -- 评论的分数 ABANDON\n\t-- com_scope int UNSIGNED default 0,\n\n\tprimary key(com_id),\n    foreign key(com_cus_id) references Customer(cus_id),\n\tforeign key(com_art_id) references Article(art_id)\n);\n\n\n-- rep 回复\nDROP TABLE IF EXISTS NR.Reply;\nCREATE TABLE NR.Reply (\n    rep_id INT UNSIGNED NOT NULL auto_increment,\n    rep_content TEXT,\n    -- 回复的类型, 0 是对评论的回复, 1 是对回复的回复\n    rep_type tinyint default 0, \n    rep_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n\trep_legal tinyint default 0,\n    -- 爬虫过程中的评论标识\n    rep_spider varchar(64) default '',\n    rep_cus_id INT UNSIGNED,\n    rep_art_id INT UNSIGNED,\n    rep_com_id INT UNSIGNED, \n    rep_rep_id INT UNSIGNED,\n\n    -- ABANDON\n    -- rep_like_num INT UNSIGNED default 0,\n    -- ABANDON\n    -- rep_dislike_num INT UNSIGNED default 0,\n\t-- 回复的回复数量 ABANDON\n    -- rep_reply_num INT UNSIGNED default 0,\n    -- 回复的分数 ABANDON\n\t-- rep_scope int UNSIGNED default 0,\n\n    primary key(rep_id),\n    foreign key(rep_cus_id) references Customer(cus_id),\n\tforeign key(rep_art_id) references Article(art_id),\n    foreign key(rep_com_id) references Comment(com_id),\n    foreign key(rep_rep_id) references Reply(rep_id)\n);\n\n\n-- adm 管理员\nDROP TABLE IF EXISTS NR.Administrator;\nCREATE TABLE NR.Administrator (\n    adm_id INT UNSIGNED NOT NULL auto_increment,\n    adm_name VARCHAR(64),\n    adm_pass VARCHAR(255),\n    adm_email VARCHAR(64),\n    adm_phone VARCHAR(64),\n    adm_address VARCHAR(255),\n    adm_avatar_url VARCHAR(255),\n    adm_gender TINYINT DEFAULT 0,\n    adm_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    \n    primary key(adm_id)\n);\n\n\n\n-- ccf 用户的关注情况记录\n-- follower -> followee\n-- DROP TABLE IF EXISTS NewsRecommend.CustomerCustomerFollow;\n-- CREATE TABLE NewsRecommend.CustomerCustomerFollow (\n--     ccf_id INT UNSIGNED NOT NULL auto_increment,\n--     ccf_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n\n--     ccf_follower_id INT UNSIGNED,\n--     ccf_followee_id INT UNSIGNED,\n-- \tprimary key(ccf_id),\n--     foreign key(ccf_follower_id) references Customers(cus_id),\n--     foreign key(ccf_followee_id) references Customers(cus_id)\n-- );\n\n\n\n-- cbr 用户的行为记录\n-- 此表比较复杂, 用户之间的关注, 用户对文章, 用户对评论, 用户对回复. \nDROP TABLE IF EXISTS NR.CusBehaviorRecord;\nCREATE TABLE NR.CusBehaviorRecord (\n    cbr_id INT UNSIGNED NOT NULL auto_increment,\n    -- 用户 攻\n    cbr_cus_id_from INT UNSIGNED,\n    -- 用户 受\n    cbr_cus_id_to INT UNSIGNED,\n    -- 行为类别\n    cbr_behavior INT default 0,\n    -- 行为时间\n    cbr_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    -- 行为发生的文章 ID\n    cbr_art_id INT UNSIGNED,\n    -- 行为发生的位置代号, 0: 无发生, 1: 文章, 2: 评论, 3:回复\n    cbr_type TINYINT DEFAULT 0,\n    -- target ID\n    cbr_target_id INT UNSIGNED,\n    \n\tprimary key(cbr_id),\n    foreign key(cbr_art_id) references Article(art_id),\n    foreign key(cbr_cus_id_from) references Customer(cus_id),\n    foreign key(cbr_cus_id_to) references Customer(cus_id)\n);\n\n-- afc 文章特征统计表\nDROP TABLE IF EXISTS NR.ArtFeatureCount;\nCREATE TABLE NR.ArtFeatureCount (\n    afc_id INT UNSIGNED NOT NULL auto_increment,\n    afc_art_id INT UNSIGNED NOT NULL,\n\n    afc_like_num INT UNSIGNED default 0,\n    afc_dislike_num INT UNSIGNED default 0,\n    afc_com_num INT UNSIGNED default 0,\n    afc_rep_num INT UNSIGNED default 0,\n    afc_read_num INT UNSIGNED default 0,\n    afc_art_time TIMESTAMP,\n\n\tprimary key(afc_id),\n    foreign key(afc_art_id) references Article(art_id)\n);\n\n\n-- cfc 用户特征统计表\nDROP TABLE IF EXISTS NR.CusFeatureCount;\nCREATE TABLE NR.CusFeatureCount (\n    cfc_id INT UNSIGNED NOT NULL auto_increment,\n\n    cfc_cus_id INT UNSIGNED NOT NULL,\n\n    cfc_news_society INT UNSIGNED default 0,\n    cfc_news_entertainment INT UNSIGNED default 0,\n    cfc_news_tech INT UNSIGNED default 0,\n    cfc_news_military INT UNSIGNED default 0,\n    cfc_news_sports INT UNSIGNED default 0,\n    cfc_news_finance INT UNSIGNED default 0,\n    cfc_news_world INT UNSIGNED default 0,\n    cfc_news_fashion INT UNSIGNED default 0,\n    cfc_news_travel INT UNSIGNED default 0,\n    cfc_news_discovery INT UNSIGNED default 0,\n    cfc_news_baby INT UNSIGNED default 0,\n    cfc_news_regimen INT UNSIGNED default 0,\n    cfc_news_story INT UNSIGNED default 0,\n    cfc_news_essay INT UNSIGNED default 0,\n    cfc_news_game INT UNSIGNED default 0,\n    cfc_news_history INT UNSIGNED default 0,\n    cfc_news_food INT UNSIGNED default 0,\n    cfc_news_car INT UNSIGNED default 0,\n\n\tprimary key(cfc_id),\n    foreign key(cfc_cus_id) references Customer(cus_id)\n);\n\n-- crr 推荐内容记录表\nDROP TABLE IF EXISTS NR.CusRecommendRecord;\nCREATE TABLE NR.CusRecommendRecord (\n    crr_id INT UNSIGNED NOT NULL auto_increment,\n    crr_cus_id INT UNSIGNED NOT NULL,\n    crr_art_id INT UNSIGNED NOT NULL,\n    crr_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n\n\tprimary key(crr_id),\n    foreign key(crr_cus_id) references Customer(cus_id),\n    foreign key(crr_art_id) references Article(art_id)\n);\n\n\n-- 新闻 分数 for tiny 列表 asl\nDROP VIEW IF EXISTS NR.ArtScoreList;\ncreate view NR.ArtScoreList(asl_art_id, asl_art_score) as\n    select\n        afc_art_id,\n        timestampdiff(HOUR,now(),afc_art_time)*20+cast(afc_like_num as signed)*4+cast(afc_dislike_num as signed)*(-6)+cast(afc_com_num as signed)*3+cast(afc_read_num as signed )*1+cast(afc_rep_num as signed )*2 as afc_art_socre\n    from NR.ArtFeatureCount\n    order by afc_art_socre desc;\n\n-- 新闻 分数 for hot 列表 atl\nDROP VIEW IF EXISTS NR.ArtTimeList;\ncreate view NR.ArtTimeList(atl_art_id, atl_art_score) as \n    SELECT\n        afc_art_id,\n        timestampdiff(HOUR,now(),afc_art_time)*32+cast(afc_like_num as signed)*4+cast(afc_dislike_num as signed)*(-6)+cast(afc_com_num as signed)*3+cast(afc_read_num as signed )*1+cast(afc_rep_num as signed )*2 as atl_art_score\n    from NR.ArtFeatureCount left join NR.Article on NR.ArtFeatureCount.afc_art_id = NR.Article.art_id\n    where\n        NR.Article.art_type in (\"news_society\", \"news_military\", \"news_finance\", \"news_entertainment\",\n                                \"news_game\", \"news_sports\", \"news_world\", \"news_tech\", \"news_car\", \"news_fashion\") and\n        abs(timestampdiff(HOUR,now(),afc_art_time)) < 72\n    order by atl_art_score desc;\n"
  },
  {
    "path": "README.md",
    "content": "# NewsRecommend\n\n基于协同过滤算法的新闻推荐系统, 项目分前后端与爬虫. \n\n实现热点新闻推荐以及个性化新闻推荐.\n\n[项目的具体说明](https://smacul.github.io/log/news_recommend/)\n\n喜欢的话, 可以点个 star 奥. \n\n## 项目分支\n\n- main: 主分支, 保存最新的可预览状态.\n- dev: Mac 上的开发分支\n- dev-win: Win 上的开发分支\n\n**不同分支使用的数据库名称可能并不一致, 以各个分支中的 `NewsRecommend.sql` 文件为准**\n\n## 数据库 NewsRecommend.sql\nMySQL 导入自动建库\n\n## 爬虫 spider\n\n### 运行\n爬虫独立运行获取数据后写入数据库, 数据来源为 今日头条, 需要 python 3 环境.\n\n在 `spider` 目录下创建 `properties/database.json`.   \n*database.json* 模板：\n``` json\n{\n  \"name\": \"NewsRecommend\",\n  \"user\": \"your name\",\n  \"pass\": \"your pass\",\n  \"host\": \"your host\",\n  \"charset\": \"utf8mb4\"\n}\n```\n\n并在 `spider` 目录下创建 `log` 目录，用于存放日志文件 (我懒得写)\n\n正确安装 webdriver 后执行：\n\n``` sh\ncd spider\npython Main.py\n```\n\n## 前端 front\n\n前端利用 Vue Cli 3 脚手架. 需要 node.js yarn.\n\n应该需要先装 wangeditor (富文本编辑工具) `npm install wangeditor`\n\n### 运行\n``` sh\ncd front\nyarn install\nyarn serve\n```\n\n<!-- ### 页面浏览\n``` sh\nlocalhost:8071/         # 首页\nlocalhost:8071/article  # 文章阅读页\nlocalhost:8071/self     # 个人中心\nlocalhost:8071/search   # 搜索页面\n# ...\n​``` -->\n\n## 后端 back\n\n后端基于 SpringBoot 与 MyBatis. \n\n现在工程目录下的 `src/main/resources` 中创建 application.properties 文件, 内容大致如下: \n\n``` shell   \nspring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.url = jdbc:mysql://[主机名]:3306/[数据库名称]?useUnicode=true&characterEncoding=utf8&useSSL=true\nspring.datasource.username = [用户名]\nspring.datasource.password = [密码]\nmybatis.configuration.map-underscore-to-camel-case=true\nmybatis.mapper-locations=classpath:mapper/*.xml\nmybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl\n```\n\n## 预览\n\n![首页](./index.png)\n\n"
  },
  {
    "path": "back/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**\n!**/src/test/**\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n\n### VS Code ###\n.vscode/\n\n/src/main/resources/application.properties\n"
  },
  {
    "path": "back/.mvn/wrapper/MavenWrapperDownloader.java",
    "content": "/*\n * Copyright 2012-2019 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport java.net.*;\nimport java.io.*;\nimport java.nio.channels.*;\nimport java.util.Properties;\n\npublic class MavenWrapperDownloader {\n\n    private static final String WRAPPER_VERSION = \"0.5.5\";\n    /**\n     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.\n     */\n    private static final String DEFAULT_DOWNLOAD_URL = \"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/\"\n            + WRAPPER_VERSION + \"/maven-wrapper-\" + WRAPPER_VERSION + \".jar\";\n\n    /**\n     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to\n     * use instead of the default one.\n     */\n    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =\n            \".mvn/wrapper/maven-wrapper.properties\";\n\n    /**\n     * Path where the maven-wrapper.jar will be saved to.\n     */\n    private static final String MAVEN_WRAPPER_JAR_PATH =\n            \".mvn/wrapper/maven-wrapper.jar\";\n\n    /**\n     * Name of the property which should be used to override the default download url for the wrapper.\n     */\n    private static final String PROPERTY_NAME_WRAPPER_URL = \"wrapperUrl\";\n\n    public static void main(String args[]) {\n        System.out.println(\"- Downloader started\");\n        File baseDirectory = new File(args[0]);\n        System.out.println(\"- Using base directory: \" + baseDirectory.getAbsolutePath());\n\n        // If the maven-wrapper.properties exists, read it and check if it contains a custom\n        // wrapperUrl parameter.\n        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);\n        String url = DEFAULT_DOWNLOAD_URL;\n        if (mavenWrapperPropertyFile.exists()) {\n            FileInputStream mavenWrapperPropertyFileInputStream = null;\n            try {\n                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);\n                Properties mavenWrapperProperties = new Properties();\n                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);\n                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);\n            } catch (IOException e) {\n                System.out.println(\"- ERROR loading '\" + MAVEN_WRAPPER_PROPERTIES_PATH + \"'\");\n            } finally {\n                try {\n                    if (mavenWrapperPropertyFileInputStream != null) {\n                        mavenWrapperPropertyFileInputStream.close();\n                    }\n                } catch (IOException e) {\n                    // Ignore ...\n                }\n            }\n        }\n        System.out.println(\"- Downloading from: \" + url);\n\n        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);\n        if (!outputFile.getParentFile().exists()) {\n            if (!outputFile.getParentFile().mkdirs()) {\n                System.out.println(\n                        \"- ERROR creating output directory '\" + outputFile.getParentFile().getAbsolutePath() + \"'\");\n            }\n        }\n        System.out.println(\"- Downloading to: \" + outputFile.getAbsolutePath());\n        try {\n            downloadFileFromURL(url, outputFile);\n            System.out.println(\"Done\");\n            System.exit(0);\n        } catch (Throwable e) {\n            System.out.println(\"- Error downloading\");\n            e.printStackTrace();\n            System.exit(1);\n        }\n    }\n\n    private static void downloadFileFromURL(String urlString, File destination) throws Exception {\n        if (System.getenv(\"MVNW_USERNAME\") != null && System.getenv(\"MVNW_PASSWORD\") != null) {\n            String username = System.getenv(\"MVNW_USERNAME\");\n            char[] password = System.getenv(\"MVNW_PASSWORD\").toCharArray();\n            Authenticator.setDefault(new Authenticator() {\n                @Override\n                protected PasswordAuthentication getPasswordAuthentication() {\n                    return new PasswordAuthentication(username, password);\n                }\n            });\n        }\n        URL website = new URL(urlString);\n        ReadableByteChannel rbc;\n        rbc = Channels.newChannel(website.openStream());\n        FileOutputStream fos = new FileOutputStream(destination);\n        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);\n        fos.close();\n        rbc.close();\n    }\n\n}\n"
  },
  {
    "path": "back/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar\n"
  },
  {
    "path": "back/mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n        \n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "back/mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    https://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar\"\n\nFOR /F \"tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%\n"
  },
  {
    "path": "back/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.2.0.RELEASE</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n    <groupId>com.smacul</groupId>\n    <artifactId>demo</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>demo</name>\n    <description>Demo project for Spring Boot</description>\n\n    <properties>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-devtools</artifactId>\n            <scope>runtime</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.junit.vintage</groupId>\n                    <artifactId>junit-vintage-engine</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot</artifactId>\n            <version>2.2.0.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-tx</artifactId>\n            <version>5.2.0.RELEASE</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>5.1.38</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13-beta-3</version>\n        </dependency>\n        <dependency>\n            <groupId>org.testng</groupId>\n            <artifactId>testng</artifactId>\n            <version>RELEASE</version>\n            <scope>compile</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/DemoApplication.java",
    "content": "package com.smacul.demo;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\n\n@EnableTransactionManagement\n@SpringBootApplication\n@MapperScan(\"com.smacul.demo.dao\")\npublic class DemoApplication {\n\n    public static void main(String[] args) {\n        SpringApplication.run(DemoApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/ArtFeatureCount.java",
    "content": "package com.smacul.demo.bean;\n\npublic class ArtFeatureCount {\n\n    private Integer afcId;\n    private Integer afcArtId;\n    private Integer afcLikeNum;\n    private Integer afcDislikeNum;\n\n    private Integer afcComNum;\n    private Integer afcRepNum;\n    private Integer afcReadNum;\n    private Integer afcArtTime;\n\n    public Integer getAfcId() {\n        return afcId;\n    }\n\n    public void setAfcId(Integer afcId) {\n        this.afcId = afcId;\n    }\n\n    public Integer getAfcArtId() {\n        return afcArtId;\n    }\n\n    public void setAfcArtId(Integer afcArtId) {\n        this.afcArtId = afcArtId;\n    }\n\n    public Integer getAfcLikeNum() {\n        return afcLikeNum;\n    }\n\n    public void setAfcLikeNum(Integer afcLikeNum) {\n        this.afcLikeNum = afcLikeNum;\n    }\n\n    public Integer getAfcDislikeNum() {\n        return afcDislikeNum;\n    }\n\n    public void setAfcDislikeNum(Integer afcDislikeNum) {\n        this.afcDislikeNum = afcDislikeNum;\n    }\n\n    public Integer getAfcComNum() {\n        return afcComNum;\n    }\n\n    public void setAfcComNum(Integer afcComNum) {\n        this.afcComNum = afcComNum;\n    }\n\n    public Integer getAfcRepNum() {\n        return afcRepNum;\n    }\n\n    public void setAfcRepNum(Integer afcRepNum) {\n        this.afcRepNum = afcRepNum;\n    }\n\n    public Integer getAfcReadNum() {\n        return afcReadNum;\n    }\n\n    public void setAfcReadNum(Integer afcReadNum) {\n        this.afcReadNum = afcReadNum;\n    }\n\n    public Integer getAfcArtTime() {\n        return afcArtTime;\n    }\n\n    public void setAfcArtTime(Integer afcArtTime) {\n        this.afcArtTime = afcArtTime;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/ArtScoreList.java",
    "content": "package com.smacul.demo.bean;\n\npublic class ArtScoreList {\n\n    private Integer aslArtId;\n    private Integer aslArtScore;\n\n    public Integer getAslArtId() {\n        return aslArtId;\n    }\n\n    public void setAslArtId(Integer aslArtId) {\n        this.aslArtId = aslArtId;\n    }\n\n    public Integer getAslArtScore() {\n        return aslArtScore;\n    }\n\n    public void setAslArtScore(Integer aslArtScore) {\n        this.aslArtScore = aslArtScore;\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/ArtTimeList.java",
    "content": "package com.smacul.demo.bean;\n\npublic class ArtTimeList {\n\n    private Integer atlId;\n    private Integer atlArtScore;\n\n    public Integer getAtlId() {\n        return atlId;\n    }\n\n    public void setAtlId(Integer atlId) {\n        this.atlId = atlId;\n    }\n\n    public Integer getAtlArtScore() {\n        return atlArtScore;\n    }\n\n    public void setAtlArtScore(Integer atlArtScore) {\n        this.atlArtScore = atlArtScore;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/Article.java",
    "content": "package com.smacul.demo.bean;\n\nimport java.sql.Timestamp;\n\npublic class Article {\n    private Integer artId;\n    private String artTitle;\n    private String artContent;\n    private String artSpider;\n\n    private String artType;\n    private String artTags;\n    private String artImageUrl;\n    private Timestamp artTime;\n\n    private Integer artLegal;\n    private Integer artCusId;\n\n    public Integer getArtId() {\n        return artId;\n    }\n\n    public void setArtId(Integer artId) {\n        this.artId = artId;\n    }\n\n    public String getArtTitle() {\n        return artTitle;\n    }\n\n    public void setArtTitle(String artTitle) {\n        this.artTitle = artTitle;\n    }\n\n    public String getArtContent() {\n        return artContent;\n    }\n\n    public void setArtContent(String artContent) {\n        this.artContent = artContent;\n    }\n\n    public String getArtSpider() {\n        return artSpider;\n    }\n\n    public void setArtSpider(String artSpider) {\n        this.artSpider = artSpider;\n    }\n\n    public String getArtType() {\n        return artType;\n    }\n\n    public void setArtType(String artType) {\n        this.artType = artType;\n    }\n\n    public String getArtTags() {\n        return artTags;\n    }\n\n    public void setArtTags(String artTags) {\n        this.artTags = artTags;\n    }\n\n    public String getArtImageUrl() {\n        return artImageUrl;\n    }\n\n    public void setArtImageUrl(String artImageUrl) {\n        this.artImageUrl = artImageUrl;\n    }\n\n    public Timestamp getArtTime() {\n        return artTime;\n    }\n\n    public void setArtTime(Timestamp artTime) {\n        this.artTime = artTime;\n    }\n\n    public Integer getArtLegal() {\n        return artLegal;\n    }\n\n    public void setArtLegal(Integer artLegal) {\n        this.artLegal = artLegal;\n    }\n\n    public Integer getArtCusId() {\n        return artCusId;\n    }\n\n    public void setArtCusId(Integer artCusId) {\n        this.artCusId = artCusId;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/Comment.java",
    "content": "package com.smacul.demo.bean;\n\nimport java.sql.Timestamp;\n\npublic class Comment {\n\n    private Integer comId;\n    private String comContent;\n    private Timestamp comTime;\n    private Integer comLegal;\n    private String comSpider;\n\n    private Integer comCusId;\n    private  Integer comArtId;\n\n    public Integer getComId() {\n        return comId;\n    }\n\n    public void setComId(Integer comId) {\n        this.comId = comId;\n    }\n\n    public String getComContent() {\n        return comContent;\n    }\n\n    public void setComContent(String comContent) {\n        this.comContent = comContent;\n    }\n\n    public Timestamp getComTime() {\n        return comTime;\n    }\n\n    public void setComTime(Timestamp comTime) {\n        this.comTime = comTime;\n    }\n\n    public Integer getComLegal() {\n        return comLegal;\n    }\n\n    public void setComLegal(Integer comLegal) {\n        this.comLegal = comLegal;\n    }\n\n    public String getComSpider() {\n        return comSpider;\n    }\n\n    public void setComSpider(String comSpider) {\n        this.comSpider = comSpider;\n    }\n\n    public Integer getComCusId() {\n        return comCusId;\n    }\n\n    public void setComCusId(Integer comCusId) {\n        this.comCusId = comCusId;\n    }\n\n    public Integer getComArtId() {\n        return comArtId;\n    }\n\n    public void setComArtId(Integer comArtId) {\n        this.comArtId = comArtId;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/CusBehaviorRecord.java",
    "content": "package com.smacul.demo.bean;\n\nimport java.sql.Timestamp;\n\npublic class CusBehaviorRecord {\n\n    private Integer cbrId;\n    private Integer cbrCusIdFrom;\n    private Integer cbrCusIdTo;\n    private Integer cbrBehavior;\n\n    private Timestamp cbrTime;\n    private Integer cbrArtId;\n    // 行为发生的位置代号, 0: 默认, 1: 文章, 2: 评论, 3:回复\n    private Integer cbrType;\n    private Integer cbrTargetId;\n\n    public Integer getCbrId() {\n        return cbrId;\n    }\n\n    public void setCbrId(Integer cbrId) {\n        this.cbrId = cbrId;\n    }\n\n    public Integer getCbrCusIdFrom() {\n        return cbrCusIdFrom;\n    }\n\n    public void setCbrCusIdFrom(Integer cbrCusIdFrom) {\n        this.cbrCusIdFrom = cbrCusIdFrom;\n    }\n\n    public Integer getCbrCusIdTo() {\n        return cbrCusIdTo;\n    }\n\n    public void setCbrCusIdTo(Integer cbrCusIdTo) {\n        this.cbrCusIdTo = cbrCusIdTo;\n    }\n\n    public Integer getCbrBehavior() {\n        return cbrBehavior;\n    }\n\n    public void setCbrBehavior(Integer cbrBehavior) {\n        this.cbrBehavior = cbrBehavior;\n    }\n\n    public Timestamp getCbrTime() {\n        return cbrTime;\n    }\n\n    public void setCbrTime(Timestamp cbrTime) {\n        this.cbrTime = cbrTime;\n    }\n\n    public Integer getCbrArtId() {\n        return cbrArtId;\n    }\n\n    public void setCbrArtId(Integer cbrArtId) {\n        this.cbrArtId = cbrArtId;\n    }\n\n    public Integer getCbrType() {\n        return cbrType;\n    }\n\n    public void setCbrType(Integer cbrType) {\n        this.cbrType = cbrType;\n    }\n\n    public Integer getCbrTargetId() {\n        return cbrTargetId;\n    }\n\n    public void setCbrTargetId(Integer cbrTargetId) {\n        this.cbrTargetId = cbrTargetId;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/CusFeatureCount.java",
    "content": "package com.smacul.demo.bean;\n\npublic class CusFeatureCount {\n    private Integer cfcId;\n    private Integer cfcCusId;\n\n    private Integer cfcNewsSociety;\n    private Integer cfcNewsEntertainment;\n    private Integer cfcNewsTech;\n\n    private Integer cfcNewsMilitary;\n    private Integer cfcNewsSports;\n    private Integer cfcNewsFinance;\n\n    private Integer cfcNewsWorld;\n    private Integer cfcNewsFashion;\n    private Integer cfcNewsTravel;\n\n    private Integer cfcNewsDiscovery;\n    private Integer cfcNewsBaby;\n    private Integer cfcNewsRegimen;\n\n    private Integer cfcNewsStory;\n    private Integer cfcNewsEssay;\n    private Integer cfcNewsGame;\n\n    private Integer cfcNewsHistory;\n    private Integer cfcNewsFood;\n    private Integer cfcNewsCar;\n\n    public Integer getCfcId() {\n        return cfcId;\n    }\n\n    public void setCfcId(Integer cfcId) {\n        this.cfcId = cfcId;\n    }\n\n    public Integer getCfcCusId() {\n        return cfcCusId;\n    }\n\n    public void setCfcCusId(Integer cfcCusId) {\n        this.cfcCusId = cfcCusId;\n    }\n\n    public Integer getCfcNewsSociety() {\n        return cfcNewsSociety;\n    }\n\n    public void setCfcNewsSociety(Integer cfcNewsSociety) {\n        this.cfcNewsSociety = cfcNewsSociety;\n    }\n\n    public Integer getCfcNewsEntertainment() {\n        return cfcNewsEntertainment;\n    }\n\n    public void setCfcNewsEntertainment(Integer cfcNewsEntertainment) {\n        this.cfcNewsEntertainment = cfcNewsEntertainment;\n    }\n\n    public Integer getCfcNewsTech() {\n        return cfcNewsTech;\n    }\n\n    public void setCfcNewsTech(Integer cfcNewsTech) {\n        this.cfcNewsTech = cfcNewsTech;\n    }\n\n    public Integer getCfcNewsMilitary() {\n        return cfcNewsMilitary;\n    }\n\n    public void setCfcNewsMilitary(Integer cfcNewsMilitary) {\n        this.cfcNewsMilitary = cfcNewsMilitary;\n    }\n\n    public Integer getCfcNewsSports() {\n        return cfcNewsSports;\n    }\n\n    public void setCfcNewsSports(Integer cfcNewsSports) {\n        this.cfcNewsSports = cfcNewsSports;\n    }\n\n    public Integer getCfcNewsFinance() {\n        return cfcNewsFinance;\n    }\n\n    public void setCfcNewsFinance(Integer cfcNewsFinance) {\n        this.cfcNewsFinance = cfcNewsFinance;\n    }\n\n    public Integer getCfcNewsWorld() {\n        return cfcNewsWorld;\n    }\n\n    public void setCfcNewsWorld(Integer cfcNewsWorld) {\n        this.cfcNewsWorld = cfcNewsWorld;\n    }\n\n    public Integer getCfcNewsFashion() {\n        return cfcNewsFashion;\n    }\n\n    public void setCfcNewsFashion(Integer cfcNewsFashion) {\n        this.cfcNewsFashion = cfcNewsFashion;\n    }\n\n    public Integer getCfcNewsTravel() {\n        return cfcNewsTravel;\n    }\n\n    public void setCfcNewsTravel(Integer cfcNewsTravel) {\n        this.cfcNewsTravel = cfcNewsTravel;\n    }\n\n    public Integer getCfcNewsDiscovery() {\n        return cfcNewsDiscovery;\n    }\n\n    public void setCfcNewsDiscovery(Integer cfcNewsDiscovery) {\n        this.cfcNewsDiscovery = cfcNewsDiscovery;\n    }\n\n    public Integer getCfcNewsBaby() {\n        return cfcNewsBaby;\n    }\n\n    public void setCfcNewsBaby(Integer cfcNewsBaby) {\n        this.cfcNewsBaby = cfcNewsBaby;\n    }\n\n    public Integer getCfcNewsRegimen() {\n        return cfcNewsRegimen;\n    }\n\n    public void setCfcNewsRegimen(Integer cfcNewsRegimen) {\n        this.cfcNewsRegimen = cfcNewsRegimen;\n    }\n\n    public Integer getCfcNewsStory() {\n        return cfcNewsStory;\n    }\n\n    public void setCfcNewsStory(Integer cfcNewsStory) {\n        this.cfcNewsStory = cfcNewsStory;\n    }\n\n    public Integer getCfcNewsEssay() {\n        return cfcNewsEssay;\n    }\n\n    public void setCfcNewsEssay(Integer cfcNewsEssay) {\n        this.cfcNewsEssay = cfcNewsEssay;\n    }\n\n    public Integer getCfcNewsGame() {\n        return cfcNewsGame;\n    }\n\n    public void setCfcNewsGame(Integer cfcNewsGame) {\n        this.cfcNewsGame = cfcNewsGame;\n    }\n\n    public Integer getCfcNewsHistory() {\n        return cfcNewsHistory;\n    }\n\n    public void setCfcNewsHistory(Integer cfcNewsHistory) {\n        this.cfcNewsHistory = cfcNewsHistory;\n    }\n\n    public Integer getCfcNewsFood() {\n        return cfcNewsFood;\n    }\n\n    public void setCfcNewsFood(Integer cfcNewsFood) {\n        this.cfcNewsFood = cfcNewsFood;\n    }\n\n    public Integer getCfcNewsCar() {\n        return cfcNewsCar;\n    }\n\n    public void setCfcNewsCar(Integer cfcNewsCar) {\n        this.cfcNewsCar = cfcNewsCar;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/Customer.java",
    "content": "package com.smacul.demo.bean;\n\n\nimport java.sql.Timestamp;\n\npublic class Customer {\n    private Integer cusId;\n    private String cusName;\n    private String cusPass;\n    private String cusSpider;\n\n    private String cusAvatarUrl;\n    private String cusStyle;\n    private Integer cusGender;\n    private Timestamp cusTime;\n    // cusLegal 默认为 0, 1 为合法, -1 为非法\n    private Integer cusLegal;\n\n    public Integer getCusId() {\n        return cusId;\n    }\n\n    public void setCusId(Integer cusId) {\n        this.cusId = cusId;\n    }\n\n    public String getCusName() {\n        return cusName;\n    }\n\n    public void setCusName(String cusName) {\n        this.cusName = cusName;\n    }\n\n    public String getCusPass() {\n        return cusPass;\n    }\n\n    public void setCusPass(String cusPass) {\n        this.cusPass = cusPass;\n    }\n\n    public String getCusSpider() {\n        return cusSpider;\n    }\n\n    public void setCusSpider(String cusSpider) {\n        this.cusSpider = cusSpider;\n    }\n\n    public String getCusAvatarUrl() {\n        return cusAvatarUrl;\n    }\n\n    public void setCusAvatarUrl(String cusAvatarUrl) {\n        this.cusAvatarUrl = cusAvatarUrl;\n    }\n\n    public String getCusStyle() {\n        return cusStyle;\n    }\n\n    public void setCusStyle(String cusStyle) {\n        this.cusStyle = cusStyle;\n    }\n\n    public Integer getCusGender() {\n        return cusGender;\n    }\n\n    public void setCusGender(Integer cusGender) {\n        this.cusGender = cusGender;\n    }\n\n    public Timestamp getCusTime() {\n        return cusTime;\n    }\n\n    public void setCusTime(Timestamp cusTime) {\n        this.cusTime = cusTime;\n    }\n\n    public Integer getCusLegal() {\n        return cusLegal;\n    }\n\n    public void setCusLegal(Integer cusLegal) {\n        this.cusLegal = cusLegal;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/bean/Reply.java",
    "content": "package com.smacul.demo.bean;\n\nimport java.sql.Timestamp;\n\npublic class Reply {\n\n    private Integer repId;\n    private String repContent;\n\n    private Integer repType;\n    private Timestamp repTime;\n    private Integer repLegal;\n    private String repSpider;\n\n    private Integer repCusId;\n    private Integer repArtId;\n    private Integer repComId;\n    private Integer repRepId;\n\n    public Integer getRepId() {\n        return repId;\n    }\n\n    public void setRepId(Integer repId) {\n        this.repId = repId;\n    }\n\n    public String getRepContent() {\n        return repContent;\n    }\n\n    public void setRepContent(String repContent) {\n        this.repContent = repContent;\n    }\n\n    public Integer getRepType() {\n        return repType;\n    }\n\n    public void setRepType(Integer repType) {\n        this.repType = repType;\n    }\n\n    public Timestamp getRepTime() {\n        return repTime;\n    }\n\n    public void setRepTime(Timestamp repTime) {\n        this.repTime = repTime;\n    }\n\n    public Integer getRepLegal() {\n        return repLegal;\n    }\n\n    public void setRepLegal(Integer repLegal) {\n        this.repLegal = repLegal;\n    }\n\n    public String getRepSpider() {\n        return repSpider;\n    }\n\n    public void setRepSpider(String repSpider) {\n        this.repSpider = repSpider;\n    }\n\n    public Integer getRepCusId() {\n        return repCusId;\n    }\n\n    public void setRepCusId(Integer repCusId) {\n        this.repCusId = repCusId;\n    }\n\n    public Integer getRepArtId() {\n        return repArtId;\n    }\n\n    public void setRepArtId(Integer repArtId) {\n        this.repArtId = repArtId;\n    }\n\n    public Integer getRepComId() {\n        return repComId;\n    }\n\n    public void setRepComId(Integer repComId) {\n        this.repComId = repComId;\n    }\n\n    public Integer getRepRepId() {\n        return repRepId;\n    }\n\n    public void setRepRepId(Integer repRepId) {\n        this.repRepId = repRepId;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/controller/DiscussController.java",
    "content": "package com.smacul.demo.controller;\n\nimport com.smacul.demo.bean.Comment;\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.bean.Reply;\nimport com.smacul.demo.model.ComFullMod;\nimport com.smacul.demo.service.DiscussService;\nimport com.smacul.demo.service.ShapeService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpSession;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/discuss\")\npublic class DiscussController {\n\n    @Autowired\n    DiscussService discussService;\n    @Autowired\n    ShapeService shapeService;\n    @Autowired\n    HttpSession session;\n\n    /**\n     * 获取完整的评论列表\n     * 20-04-20 方法创建\n     * @param artId\n     * @return\n     */\n    @RequestMapping(\"/page\")\n    public List<ComFullMod> getComList(@RequestParam Integer artId) {\n        Customer customer = (Customer) session.getAttribute(\"customer\");\n        if (customer == null) {\n            return null;\n        }\n        return discussService.getComList(artId);\n    }\n\n    /**\n     * 添加评论\n     * 20-04-20 添加方法\n     * 20-05-04 在插入用户行为数据之前, 对 result 的内容进行检查\n     * @param comment\n     * @return\n     */\n    @RequestMapping(\"/com\")\n    public String addNewCom(@RequestBody Comment comment) {\n        Customer customer = (Customer) session.getAttribute(\"customer\");\n        if (customer == null) {\n            return \"评论失败\";\n        }\n        String result = discussService.addNewCom(comment);\n        if (result.equals(\"评论成功\")) {\n            shapeService.setCusBehaviorComEdit(customer.getCusId(), comment.getComArtId(), comment.getComId());\n        }\n        return result;\n    }\n\n    /**\n     * 添加回复\n     * 20-04-20 添加方法\n     * 20-05-04 在插入用户行为数据之前, 对 result 的内容进行检查\n     * @param reply\n     * @return\n     */\n    @RequestMapping(\"/rep\")\n    public String addNewRep(@RequestBody Reply reply) {\n        Customer customer = (Customer) session.getAttribute(\"customer\");\n        if (customer == null) {\n            return \"评论失败\";\n        }\n        String result = discussService.addNewRep(reply);\n        if (result.equals(\"评论成功\")) {\n            shapeService.setCusBehaviorRepEdit(customer.getCusId(), reply.getRepArtId(), reply.getRepId());\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/controller/EditController.java",
    "content": "package com.smacul.demo.controller;\n\nimport com.smacul.demo.bean.Article;\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.service.EditService;\nimport com.smacul.demo.service.ShapeService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpSession;\n\n@RestController\n@RequestMapping(\"/edit\")\npublic class EditController {\n\n    @Autowired\n    EditService editService;\n    @Autowired\n    ShapeService shapeService;\n    @Autowired\n    HttpSession session;\n\n    /**\n     * 用户添加新的文章\n     * 20-05-04 添加方法\n     * @param article\n     * @return\n     */\n    @RequestMapping(\"/add\")\n    public Integer addNewArt(@RequestBody Article article) {\n        Customer customer = (Customer) session.getAttribute(\"customer\");\n        if (customer == null) {\n            return 0;\n        }\n\n        String result = editService.addNewArt(article);\n        if (result.equals(\"文章添加成功\")) {\n            shapeService.setCusBehaviorArtEdit(customer.getCusId(), article.getArtId());\n        }\n        return article.getArtId();\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/controller/LoadController.java",
    "content": "package com.smacul.demo.controller;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.model.ArtFullMod;\nimport com.smacul.demo.service.LoadService;\nimport com.smacul.demo.service.SelfService;\nimport com.smacul.demo.service.SessionService;\nimport com.smacul.demo.service.ShapeService;\nimport com.smacul.demo.util.TypeHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpSession;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/load\")\npublic class LoadController {\n\n    @Autowired\n    LoadService loadService;\n    @Autowired\n    ShapeService shapeService;\n    @Autowired\n    SelfService selfService;\n    @Autowired\n    SessionService session;\n\n    /**\n     * 获取新闻类别(英文)\n     * 20-04-19 创建方法 TODO 老用户的处理逻辑还没完成\n     * @return\n     */\n    @RequestMapping(\"/type\")\n    public List<String> getArtTypes() {\n        Customer customer = session.getCusSession();\n        if (customer == null) {\n            return null;\n        }\n        if (selfService.checkIsNewUser(customer.getCusId())) {\n            return loadService.getArtTypesForNew();\n        } else {\n            return loadService.getArtTypesForOld(customer.getCusId());\n        }\n    }\n\n    /**\n     * 按照类别获取一页文章\n     * 20-04-19 创建方法\n     * 20-05-02 添加老用户推荐逻辑\n     * 20-05-18 修改逻辑, 在新用户切换成老用户时添加计算相似用户的逻辑\n     * 20-05-19 推荐逻辑修改, 在相似用户用完之后, 重新计算相似用户\n     * 20-05-24 方法修改, 接受 artType 后转换为英文.\n     * @param artType\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    @RequestMapping(\"/tiny\")\n    public List<ArtFullMod> getTinyArtOnePageByType(\n            @RequestParam String artType, @RequestParam Integer page, @RequestParam Integer pageSize) {\n        artType = TypeHandler.typeTransSingleChToEn(artType);\n        Customer customer = session.getCusSession();\n        if (customer == null) {\n            return null;\n        }\n        List<ArtFullMod> recommendList = null;\n        // 新用户推荐\n        if (selfService.checkIsNewUser(customer.getCusId())) {\n            recommendList = loadService.getTinyArtOnePageByTypeForNew(customer.getCusId(), artType, session.getPagThenAddOne(artType), pageSize);\n            shapeService.recordRecommendList(customer.getCusId(), recommendList);\n            return recommendList;\n        }\n\n        // 老用户推荐\n        List<Integer> relativeCusList = session.getRelSession();\n\n        // 当前用户变为老用户, session 中相似用户的记录为空\n        if (relativeCusList == null || relativeCusList.size() == 0) {\n            relativeCusList = selfService.getRelativeCusList(customer.getCusId(), 10);\n            session.setRelSession(relativeCusList);\n            session.getSetPagAfterCusChange(artType);\n        }\n        //获取推荐内容\n        recommendList = loadService.getTinyArtOnePageByTypeForOld(\n                customer.getCusId(), relativeCusList, artType, session.getPagThenAddOne(artType), pageSize);\n        // 如果 getTinyArtOnePageByTypeForOld 方法返回内容长度为 0, 说明本批次相似用户推荐结束. 重新计算相似用户\n        // getTinyArtOnePageByTypeForOld 方法返回内容长度为 0, 系统利用新一批相似用户再次尝试推荐\n        if (recommendList.size() == 0) {\n            if (\"news_global\".equals(artType)) {\n                relativeCusList = selfService.getRelativeCusList(customer.getCusId(), 10);\n                session.setRelSession(relativeCusList);\n                session.getSetPagAfterCusChange(artType);\n                recommendList = loadService.getTinyArtOnePageByTypeForOld(customer.getCusId(), relativeCusList, artType, session.getPagThenAddOne(artType), pageSize);\n            }\n            // 如果再次推荐的结果内容长度为 0, 切换至新用户推荐\n            if (recommendList.size() == 0) {\n                if (\"news_global\".equals(artType)) {\n                    session.setRelSession(new ArrayList<>());\n                    session.getSetPagAfterCusChange(artType);\n                }\n                recommendList = loadService.getTinyArtOnePageByTypeForNew(customer.getCusId(), artType, session.getPagThenAddOne(artType), pageSize);\n            }\n        }\n        shapeService.recordRecommendList(customer.getCusId(), recommendList);\n        return recommendList;\n    }\n\n    /**\n     * 提供一页的热点新闻\n     * 20-04-19 创建方法\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    @RequestMapping(\"/hot\")\n    public List<ArtFullMod> getHotArtOnePage(@RequestParam Integer page, @RequestParam Integer pageSize) {\n        Customer customer = session.getCusSession();\n        if (customer == null) {\n            return null;\n        }\n        return loadService.getHotArtOnePage(session.getPagThenAddOne(\"news_hot\"), pageSize);\n    }\n\n    /**\n     * 获取文章的主体内容, 包括文章内容, 文章作者, 文章的特征信息, 当前用户与文章的关系.\n     * 20-04-19 创建方法\n     * @param artId\n     * @return\n     */\n    @RequestMapping(\"/main\")\n    public ArtFullMod getFullArt(@RequestParam Integer artId) {\n        Customer customer = session.getCusSession();\n        if (customer == null) {\n            return null;\n        }\n        ArtFullMod artFullMod = loadService.getFullArt(customer.getCusId(), artId);\n        shapeService.setCusBehaviorArtRead(customer.getCusId(), artId);\n        return artFullMod;\n    }\n\n    /**\n     * 文章点赞/点踩控制, 包括取消\n     * 20-04-19 创建方法\n     * @param artId\n     * @param type  1: 点赞, 2: 点踩, -1: 取消点赞, -2: 取消点踩\n     * @return\n     */\n    @RequestMapping(\"/prefer\")\n    public String setArtPreference(@RequestParam Integer artId, @RequestParam Integer type) {\n        Customer customer = session.getCusSession();\n        if (customer == null) {\n            return \"操作失败\";\n        }\n        Boolean result = false;\n        switch (type){\n            case 1:\n                result = shapeService.setCusBehaviorArtLike(customer.getCusId(), artId, true);\n                break;\n            case 2:\n                result = shapeService.setCusBehaviorArtDislike(customer.getCusId(), artId, true);\n                break;\n            case -1:\n                result = shapeService.setCusBehaviorArtLike(customer.getCusId(), artId, false);\n                break;\n            case -2:\n                result = shapeService.setCusBehaviorArtDislike(customer.getCusId(), artId, false);\n                break;\n        }\n        if (result) {\n            return \"操作成功\";\n        } else {\n            return \"操作失败\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/controller/SearchController.java",
    "content": "package com.smacul.demo.controller;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.model.ArtFullMod;\nimport com.smacul.demo.service.SearchService;\nimport com.smacul.demo.service.ShapeService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpSession;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/search\")\npublic class SearchController {\n\n    @Autowired\n    SearchService searchService;\n    @Autowired\n    ShapeService shapeService;\n    @Autowired\n    HttpSession session;\n\n    @RequestMapping(\"/simple\")\n    public List<ArtFullMod> searchContentSimple(\n            @RequestParam String key, @RequestParam Integer page, @RequestParam Integer pageSize) {\n        Customer customer = (Customer) session.getAttribute(\"customer\");\n        if (customer == null) {\n            return null;\n        }\n        return searchService.searchContentSimple(key, page, pageSize);\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/controller/SelfController.java",
    "content": "package com.smacul.demo.controller;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.dao.CusDao;\nimport com.smacul.demo.model.CusDynamicMod;\nimport com.smacul.demo.model.CusFeatureFullMod;\nimport com.smacul.demo.service.SearchService;\nimport com.smacul.demo.service.SelfService;\nimport com.smacul.demo.service.SessionService;\nimport com.smacul.demo.service.ShapeService;\nimport com.sun.org.apache.xpath.internal.operations.Bool;\nimport org.apache.ibatis.annotations.Param;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.servlet.http.HttpSession;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\n\n@RestController\n@RequestMapping(\"/self\")\npublic class SelfController {\n\n    @Autowired\n    SelfService selfService;\n    @Autowired\n    ShapeService shapeService;\n    @Autowired\n    SessionService session;\n\n    /**\n     * 用户登录\n     * 20-04-18 创建方法\n     * 20-05-02 添加获取相似用户的逻辑\n     * @param cusName\n     * @param cusPass\n     * @return\n     */\n    @RequestMapping(\"/login\")\n    public String cusLogin(@RequestParam String cusName, @RequestParam String cusPass) {\n        if (session.getCusSession() != null) {\n            return \"您已登录\";\n        }\n        try {\n            Customer customer = selfService.checkCusForLogin(cusName, cusPass);\n            if (customer != null) {\n                customer.setCusPass(null);\n                session.setCusSession(customer);\n                List<Integer> cusList = selfService.getRelativeCusList(customer.getCusId(), 10);\n                session.setRelSession(cusList);\n                session.initPagSession();\n                return \"登录成功\";\n            }\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        return \"登录失败\";\n    }\n\n    /**\n     * 用户退出登录\n     * 20-04-24 创建方法\n     * @return\n     */\n    @RequestMapping(\"/quit\")\n    public String quitLogin() {\n        session.setCusSession(null);\n        return \"退出成功\";\n    }\n\n    /**\n     * 用户注册\n     * 20-04-18 创建方法\n     * 20-04-24 逻辑修改, 在注册时清空 session 中的用户\n     * @param cusName\n     * @param cusPass\n     * @return\n     */\n    @RequestMapping(\"/register\")\n    public String cusRegister(@RequestParam String cusName, @RequestParam String cusPass) {\n        try {\n            session.setCusSession(null);\n            return selfService.setNewCus(cusName, cusPass);\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        return \"注册失败\";\n    }\n\n    /**\n     * 通过 ID 获取用户基本信息\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    @RequestMapping(\"/basic\")\n    public Customer getCusBasicInfo(@RequestParam Integer cusId) {\n        if (session.getCusSession() == null) {\n            return null;\n        }\n        if (cusId == null || cusId <= 0) {\n            return session.getCusSession();\n        } else {\n            return selfService.getCusBasicInfo(cusId);\n        }\n    }\n\n    /**\n     * 修改用户的基本信息\n     * 20-04-18 创建方法\n     * @param customer\n     * @return\n     */\n    @RequestMapping(\"/modify\")\n    public String setCusBasicInfo(@RequestBody Customer customer) {\n        if (session.getCusSession() == null) {\n            return \"修改失败\";\n        }\n        try {\n            if (selfService.setCusBasicInfo(customer)) {\n                session.setCusSession(customer);\n                return \"修改成功\";\n            }\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n        return \"修改失败\";\n    }\n\n    /**\n     * 处理用户关注与取消关注\n     * 20-04-18 创建方法\n     * 20-04-26 修改逻辑, 防止用户关注自己\n     * 20-05-17 补上用户关注后, 更新后台三个表信息.\n     * @param cusId 关注或取消关注的用户的 ID\n     * @return\n     */\n    @RequestMapping(\"/follow\")\n    public String setCusFollow(@RequestParam Integer cusId) {\n        if (session.getCusSession() == null) {\n            return \"关注失败\";\n        }\n        Customer cusFrom = session.getCusSession();\n        Integer cusIdFrom = cusFrom.getCusId();\n        if (cusId.equals(cusIdFrom)) {\n            return \"不能关注自己\";\n        }\n        if (selfService.setCusFollow(cusIdFrom, cusId)) {\n            shapeService.setCusBehaviorCusFollow(cusIdFrom, cusId);\n            return \"关注成功\";\n        } else {\n            return \"关注失败\";\n        }\n    }\n\n    /**\n     * 获取用户完成的特征数据\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    @RequestMapping(\"/feature\")\n    public CusFeatureFullMod getCusFeatureInfo(@RequestParam Integer cusId) {\n        return selfService.getCusFeatureInfo(cusId);\n    }\n\n    /**\n     * 获取指定用户的动态\n     * 20-04-24 创建方法\n     * @param cusId\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    @RequestMapping(\"/dynamic\")\n    public List<CusDynamicMod> getCusDynamic(\n            @RequestParam Integer cusId, @RequestParam Integer page, @RequestParam Integer pageSize) {\n        if (session.getCusSession() == null) {\n            return null;\n        }\n        return selfService.getCusDynamic(cusId, page, pageSize);\n    }\n\n    /**\n     * 检查用户之间是否存在关注关系\n     * 20-04-26 创建方法\n     * @param cusId\n     * @return\n     */\n    @RequestMapping(\"/chefollow\")\n    public Boolean checkCusFollow(@RequestParam Integer cusId) {\n        Customer cusFrom = session.getCusSession();\n        if (cusFrom == null) {\n            return false;\n        }\n        return selfService.checkCusFollow(cusFrom.getCusId(), cusId);\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/ArtDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.Article;\nimport com.smacul.demo.model.ArtFullMod;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.Collection;\nimport java.util.List;\n\n@Repository\npublic interface ArtDao {\n\n    /**\n     * 获取文章类别列表并按照数量排序\n     * 20-04-18 创建方法\n     * @return\n     */\n    List<String> getArtTypesOrderByTypeNum();\n\n    /**\n     * 全局获取一页文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 20-04-19 创建方法\n     * 20-04-23 BUG 修改, SQL 多了一个逗号\n     * 20-04-24 方法修改, 替换了排序方式\n     * 20-04-28 方法修改, 添加了用户浏览内容去重\n     * 20-05-02 修改方法名称, 添加了 New 的后缀\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    @Deprecated\n    List<ArtFullMod> getTinyArtOnePageFromGlobalNew(Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 按照类别获取一页文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 20-04-19 创建方法\n     * 20-04-23 BUG 修改, SQL 多了一个逗号; 参数 type 修改为 artType\n     * 20-04-24 方法修改, 替换了排序方式\n     * 20-04-28 方法修改, 添加了用户浏览内容去重\n     * 20-05-02 修改方法名称, 添加了 New 的后缀\n     * @param artType\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyArtOnePageByTypeNew(String artType, Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 获取一页热点新闻的文章缩略信息, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 20-04-19 创建方法\n     * 20-04-23 BUG 修改, SQL 多了一个逗号\n     * 20-04-24 方法修改, 替换了排序方式\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getHotArtOnePage(Integer start, Integer pageSize);\n\n    /**\n     * 获取一篇文章的信息, 包括文章基本信息(包含 content), 文章作者基本信息, 文章的特征统计信息\n     * 20-04-19 创建方法\n     * @param artId\n     * @return\n     */\n    ArtFullMod getArtFull(Integer artId);\n\n    /**\n     * 通过文章 ID 获取文章作者的 ID\n     * 20-04-19 创建方法\n     * @param artId\n     * @return\n     */\n    Integer getArtCusIdByArtId(Integer artId);\n\n    /**\n     * 通过文章 ID 获取文章类别\n     * 20-04-19 创建方法\n     * @param artId\n     * @return\n     */\n    String getArtTypeByArtId(Integer artId);\n\n    /**\n     * 简单的搜索功能\n     * 20-04-20 创建方法\n     * 20-04-23 BUG 修改, SQL 多了一个逗号; 删除了 SQL 中不必要的字段.\n     * 20-04-24 方法修改, 替换了排序方式\n     * @param key\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> searchContentSimple(String key, Integer start, Integer pageSize);\n\n    /**\n     * 返回一篇文章的基本信息\n     * 20-04-24 创建方法\n     * @param flag      用来判断此查询是否要生效, 生效值 非 11.\n     * @param artId\n     * @return\n     */\n    ArtFullMod getSingleArt(Integer flag, Integer artId);\n\n    /**\n     * 通过相似用户获取推荐内容\n     * 20-05-02 创建方法\n     * @param cusId\n     * @param cusIdListStr\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyArtOnePageFromGlobalOld\n            (Integer cusId, String cusIdListStr, Integer start, Integer pageSize);\n\n    /**\n     * 通过相似用户获取推荐内容, 按照类别\n     * 20-05-02 创建方法\n     * @param artType\n     * @param cusId\n     * @param cusIdListStr\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyArtOnePageByTypeOld\n            (String artType, Integer cusId, String cusIdListStr, Integer start, Integer pageSize);\n\n    /**\n     * 添加新闻\n     * 20-05-04 创建方法\n     * 20-05-11 Bug 修改, 添加插入 artLegal\n     * @param article\n     * @return\n     */\n    Integer addArt(Article article);\n\n    /**\n     * 全局获取一页新(new)文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 直接依据新闻的发布时间排序推荐.\n     * 20-05-13 创建方法\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyNewArtFromGlobalForNew(Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 全局获取一页核心(hot)文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 通过文章类别来判断是否属于核心文章\n     * 20-05-13 创建方法\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyHotArtFromGlobalForNew(Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 全局获取一页咨询类(info)文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 通过文章类别来判断是否属于核心文章\n     * 20-05-13 创建方法\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyInfoArtFromGlobalForNew(Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 按照类别获取一页新(new)文章缩略内容, 包括文章基本信息, 文章作者基本信息, 文章的特征统计信息\n     * 直接按照新闻发布的时间排序, 推荐最新的文章\n     * 20-05-13 创建方法\n     * @param artType\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyNewArtByTypeForNew(String artType, Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 此方法功能和 getTinyNewArtFromGlobalForNew 一致, 只是名字不同\n     * 20-05-13 创建方法\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyNewArtFromGlobalForOld(Integer cusId, Integer start, Integer pageSize);\n\n    /**\n     * 此方法功能和 getTinyNewArtByTypeForNew 一致, 只是名字不同\n     * 20-05-13 创建方法\n     * @param artType\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyNewArtByTypeForOld(String artType, Integer cusId, Integer start, Integer pageSize);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/ArtFeatureCountDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.ArtFeatureCount;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface ArtFeatureCountDao {\n\n    /**\n     * 获取文章的特征统计数据\n     * 20-04-18 创建方法\n     * @param artId\n     * @return\n     */\n    ArtFeatureCount getArtFeatureCountByArtId(Integer artId);\n\n    /**\n     * 更新文章指定字段的特征数据\n     * 20-04-19 创建方法\n     * 20-05-28 补丁, 数据库表缺陷\n     * @param artId\n     * @param column    特征字段, 保证 afc 前缀, 下划线\n     * @param num\n     * @return\n     */\n    Integer updateArtFeature(Integer artId, String column, Integer num);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/ArtScoreListDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface ArtScoreListDao {\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/ArtTimeList.java",
    "content": "package com.smacul.demo.dao;\n\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface ArtTimeList {\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/ComDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.Comment;\nimport com.smacul.demo.model.ComFullMod;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface ComDao {\n\n    /**\n     * 获取评论列表\n     * 20-04-20 创建方法\n     * @param artId\n     * @return\n     */\n    List<ComFullMod> getComFullList(Integer artId);\n\n    /**\n     * 添加评论\n     * 20-04-10 创建方法\n     * 20-04-24 允许评论后返回自增主键\n     * @param comment\n     * @return\n     */\n    Integer addCom(Comment comment);\n\n    /**\n     * 获取单一一条评论, 不包括其回复\n     * 20-04-24 创建方法\n     * @param flag      用来判断是否需要查询, 生效值为 2\n     * @param comId\n     * @return\n     */\n    ComFullMod getSingleCom(Integer flag, Integer comId);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/CusBehaviorRecordDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.CusBehaviorRecord;\nimport com.smacul.demo.model.CusDynamicMod;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface CusBehaviorRecordDao {\n\n    /**\n     * 统计指定两个用户之间关注行为记录的数量\n     * 20-04-18 添加方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Integer countTargetCusFollowBehavior(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 删除指定两个用户之间的关注行为记录\n     * 20-04-18 添加方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Integer deleteTargetCusFollowBehavior(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 添加指定两个用户之间的关注行为记录\n     * 20-04-18 添加方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Integer addTargetCusFollowBehavior(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 统计指定 from 用户指定行为的记录数量\n     * 20-04-18 添加方法\n     * @param cusIdFrom\n     * @param behavior\n     * @return\n     */\n    Integer countCusBehaviorFrom(Integer cusIdFrom, Integer behavior);\n\n    /**\n     * 统计指定 to 用户指定行为的记录数量\n     * 20-04-18 添加方法\n     * @param cusIdTo\n     * @param behavior\n     * @return\n     */\n    Integer countCusBehaviorTo(Integer cusIdTo, Integer behavior);\n\n    /**\n     * 统计指定 from 用户与指定文章之间指定行为的记录数量\n     * 20-04-19 创建方法\n     * 20-04-23 BUG 修复 SQL 参数错误\n     * @param cusIdFrom\n     * @param artId\n     * @param behavior\n     * @return\n     */\n    Integer countTargetCusArtBehaviorFrom(Integer cusIdFrom, Integer artId, Integer behavior);\n\n    /**\n     * 统计指定 to 用户与指定文章之间指定行为的记录数量\n     * 20-04-19 成绩方法\n     * 20-04-23 BUG 修复 SQL 参数错误\n     * @param cusIdTo\n     * @param artId\n     * @param behavior\n     * @return\n     */\n    Integer countTargetCusArtBehaviorTo(Integer cusIdTo, Integer artId, Integer behavior);\n\n    /**\n     * 插入用户行为记录\n     * 本质上, 这个方法可以取代 addTargetCusFollowBehavior\n     * 20-04-19 创建方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @param behavior\n     * @param artId\n     * @param type\n     * @param targetId\n     * @return\n     */\n    Integer addCusBehavior(\n            Integer cusIdFrom, Integer cusIdTo, Integer behavior, Integer artId, Integer type, Integer targetId);\n\n    /**\n     * 删除用户行为记录\n     * 本质上, 这个方法可以取代 deleteTargetCusFollowBehavior\n     * 20-04-19 创建方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @param behavior\n     * @param artId\n     * @param type\n     * @param targetId\n     * @return\n     */\n    Integer deleteCusBehavior(\n            Integer cusIdFrom, Integer cusIdTo, Integer behavior, Integer artId, Integer type, Integer targetId);\n\n    /**\n     * 分页获取指定用户动态\n     * 20-04-24 创建方法\n     * 20-05-06 修改排序时间\n     * @param cusId\n     * @param start\n     * @param pageSize\n     * @return\n     */\n    List<CusDynamicMod> getCusDynamicByCusId(Integer cusId, Integer start, Integer pageSize);\n\n\n    /**\n     * 获取指定用户所有的关注用户的列表\n     * 20-05-02 创建方法\n     * @param cusId\n     * @return\n     */\n    List<Integer> getFollowCus(Integer cusId);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/CusDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.Customer;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CusDao {\n\n    /**\n     * 通过用户名获取用户基本信息\n     * 20-04-18 创建方法\n     * 20-04-21 获取内容中添加密码\n     * @param cusName\n     * @return\n     */\n    Customer getCusByName(String cusName);\n\n    /**\n     * 通过统计用户数判断用户是否存在\n     * 20-04-18 创建方法\n     * @param cusName\n     * @return\n     */\n    Integer countCusByName(String cusName);\n\n    /**\n     * 在用户注册时插入用户\n     * 20-04-18 创建方法\n     * 20-04-21 参数名修改\n     * @param cusName\n     * @param cusPass   MD5 加密后的密码\n     * @return\n     */\n    Integer insertCusForRegister(String cusName, String cusPass);\n\n    /**\n     * 通过 ID 获取用户基本信息\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    Customer getCusById(Integer cusId);\n\n    /**\n     * 更新用户基本信息, 不包括密码.\n     * 20-04-18 创建方法\n     * @param customer\n     * @return\n     */\n    Integer updateCusBasicInfo(Customer customer);\n\n    /**\n     * 更新用户基本信息, 包括密码\n     * 20-04-18 创建方法\n     * @param customer\n     * @return\n     */\n    Integer updateCusBasicInfoWithPass(Customer customer);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/CusFeatureCountDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.CusFeatureCount;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface CusFeatureCountDao {\n\n    /**\n     * 获取指定 ID 用户在所有类别下的操作次数总和\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    Integer countBehaviorNum(Integer cusId);\n\n    /**\n     * 获取指定 ID 用户的类别统计数据.\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    CusFeatureCount getCusFeatureCountByCusId(Integer cusId);\n\n    /**\n     * 获取指定 ID 用户的类别统计数据(仅 18 个类别的数据)以及所有类别数据总和\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    List<Integer> getCusArtTypesBehaviorNums(Integer cusId);\n\n    /**\n     * 更新用户特征\n     * 20-04-19 创建方法\n     * @param cusId\n     * @param column    字段名, 先保证 cfc 前缀, 下划线\n     * @param num\n     * @return\n     */\n    Integer updateCusFeature(Integer cusId, String column, Integer num);\n\n    /**\n     * 初始化指定用户的特征数据记录, 即所有种类统计归 0\n     * 20-04-23 创建方法\n     * @param cusId\n     * @return\n     */\n    Integer initialCusFeature(Integer cusId);\n\n    /**\n     * 获取用户的相似用户\n     * 20-05-02 创建方法\n     * @param cusId\n     * @param num\n     * @return\n     */\n    List<Integer> getRelativeCusList(Integer cusId, Integer num);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/CusRecommendRecordDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface CusRecommendRecordDao {\n\n    /**\n     * 记录系统为用户推荐的内容\n     * 20-06-03 创建方法\n     * @param cusId\n     * @param list\n     * @return\n     */\n    Integer addRecommendList(Integer cusId, List<Integer> list);\n\n    /**\n     * 删除历史推荐记录\n     * 20-06-03 创建方法\n     * @param cusId\n     */\n    void deleteOldCommentList(Integer cusId);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/dao/RepDao.java",
    "content": "package com.smacul.demo.dao;\n\nimport com.smacul.demo.bean.Reply;\nimport com.smacul.demo.model.RepFullMod;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.List;\n\n@Repository\npublic interface RepDao {\n\n    /**\n     * 通过评论 ID 来获取此评论下所有的回复\n     * 20-04-19 创建方法\n     * 20-04-23 BUG 修复, SQL 逗号问题\n     * @param comId\n     * @return\n     */\n    List<RepFullMod> getRepFullList(Integer comId);\n\n    /**\n     * 添加回复\n     * 20-04-19 创建方法\n     * 20-04-24 允许插入后返回自增主键\n     * @param reply\n     * @return\n     */\n    Integer addRep(Reply reply);\n\n    /**\n     * 获取单一一条回复\n     * 20-04-24 创建方法\n     * @param flag      用于判断查询是否生效, 生效值位 3\n     * @param repId\n     * @return\n     */\n    RepFullMod getSingleRep(Integer flag, Integer repId);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/ArtFullMod.java",
    "content": "package com.smacul.demo.model;\n\nimport com.smacul.demo.bean.ArtFeatureCount;\nimport com.smacul.demo.bean.Customer;\n\nimport java.sql.Timestamp;\n\npublic class ArtFullMod {\n    private Integer artId;\n    private String artTitle;\n    private String artContent;\n    private String artSpider;\n\n    private String artType;\n    private String artTags;\n    private String artImageUrl;\n    private Timestamp artTime;\n\n    private Integer artLegal;\n    private Integer artCusId;\n\n    // 文章作者\n    private Customer customer;\n    private ArtFeatureCount artFeature;\n    // 浏览者-文章的行为\n    private CusArtBehaviorMod cusArtBehavior;\n\n    public Integer getArtId() {\n        return artId;\n    }\n\n    public void setArtId(Integer artId) {\n        this.artId = artId;\n    }\n\n    public String getArtTitle() {\n        return artTitle;\n    }\n\n    public void setArtTitle(String artTitle) {\n        this.artTitle = artTitle;\n    }\n\n    public String getArtContent() {\n        return artContent;\n    }\n\n    public void setArtContent(String artContent) {\n        this.artContent = artContent;\n    }\n\n    public String getArtSpider() {\n        return artSpider;\n    }\n\n    public void setArtSpider(String artSpider) {\n        this.artSpider = artSpider;\n    }\n\n    public String getArtType() {\n        return artType;\n    }\n\n    public void setArtType(String artType) {\n        this.artType = artType;\n    }\n\n    public String getArtTags() {\n        return artTags;\n    }\n\n    public void setArtTags(String artTags) {\n        this.artTags = artTags;\n    }\n\n    public String getArtImageUrl() {\n        return artImageUrl;\n    }\n\n    public void setArtImageUrl(String artImageUrl) {\n        this.artImageUrl = artImageUrl;\n    }\n\n    public Timestamp getArtTime() {\n        return artTime;\n    }\n\n    public void setArtTime(Timestamp artTime) {\n        this.artTime = artTime;\n    }\n\n    public Integer getArtLegal() {\n        return artLegal;\n    }\n\n    public void setArtLegal(Integer artLegal) {\n        this.artLegal = artLegal;\n    }\n\n    public Integer getArtCusId() {\n        return artCusId;\n    }\n\n    public void setArtCusId(Integer artCusId) {\n        this.artCusId = artCusId;\n    }\n\n    public Customer getCustomer() {\n        return customer;\n    }\n\n    public void setCustomer(Customer customer) {\n        this.customer = customer;\n    }\n\n    public ArtFeatureCount getArtFeature() {\n        return artFeature;\n    }\n\n    public void setArtFeature(ArtFeatureCount artFeature) {\n        this.artFeature = artFeature;\n    }\n\n    public CusArtBehaviorMod getCusArtBehavior() {\n        return cusArtBehavior;\n    }\n\n    public void setCusArtBehavior(CusArtBehaviorMod cusArtBehavior) {\n        this.cusArtBehavior = cusArtBehavior;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/ComFullMod.java",
    "content": "package com.smacul.demo.model;\n\nimport com.smacul.demo.bean.Customer;\n//import com.smacul.demo.bean.Reply;\n\nimport java.sql.Timestamp;\nimport java.util.List;\n\npublic class ComFullMod {\n    private Integer comId;\n    private String comContent;\n    private Timestamp comTime;\n    private Integer comLegal;\n    private String comSpider;\n\n    private Integer comCusId;\n    private Integer comArtId;\n\n    private Customer customer;\n    private List<RepFullMod> replys;\n\n    public Integer getComId() {\n        return comId;\n    }\n\n    public void setComId(Integer comId) {\n        this.comId = comId;\n    }\n\n    public String getComContent() {\n        return comContent;\n    }\n\n    public void setComContent(String comContent) {\n        this.comContent = comContent;\n    }\n\n    public Timestamp getComTime() {\n        return comTime;\n    }\n\n    public void setComTime(Timestamp comTime) {\n        this.comTime = comTime;\n    }\n\n    public Integer getComLegal() {\n        return comLegal;\n    }\n\n    public void setComLegal(Integer comLegal) {\n        this.comLegal = comLegal;\n    }\n\n    public String getComSpider() {\n        return comSpider;\n    }\n\n    public void setComSpider(String comSpider) {\n        this.comSpider = comSpider;\n    }\n\n    public Integer getComCusId() {\n        return comCusId;\n    }\n\n    public void setComCusId(Integer comCusId) {\n        this.comCusId = comCusId;\n    }\n\n    public Integer getComArtId() {\n        return comArtId;\n    }\n\n    public void setComArtId(Integer comArtId) {\n        this.comArtId = comArtId;\n    }\n\n    public Customer getCustomer() {\n        return customer;\n    }\n\n    public void setCustomer(Customer customer) {\n        this.customer = customer;\n    }\n\n    public List<RepFullMod> getReplys() {\n        return replys;\n    }\n\n    public void setReplys(List<RepFullMod> replys) {\n        this.replys = replys;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/CusArtBehaviorMod.java",
    "content": "package com.smacul.demo.model;\n\npublic class CusArtBehaviorMod {\n    private Integer cusId;\n    private Integer artId;\n    private Integer preference;\n    private Boolean isFollow;\n    private Boolean isRead;\n    private Boolean isArtAuthor;\n\n    public Integer getCusId() {\n        return cusId;\n    }\n\n    public void setCusId(Integer cusId) {\n        this.cusId = cusId;\n    }\n\n    public Integer getArtId() {\n        return artId;\n    }\n\n    public void setArtId(Integer artId) {\n        this.artId = artId;\n    }\n\n    public Integer getPreference() {\n        return preference;\n    }\n\n    public void setPreference(Integer preference) {\n        this.preference = preference;\n    }\n\n    public Boolean getFollow() {\n        return isFollow;\n    }\n\n    public void setFollow(Boolean follow) {\n        isFollow = follow;\n    }\n\n    public Boolean getRead() {\n        return isRead;\n    }\n\n    public void setRead(Boolean read) {\n        isRead = read;\n    }\n\n    public Boolean getArtAuthor() {\n        return isArtAuthor;\n    }\n\n    public void setArtAuthor(Boolean artAuthor) {\n        isArtAuthor = artAuthor;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/CusDynamicMod.java",
    "content": "package com.smacul.demo.model;\n\nimport com.smacul.demo.bean.Customer;\n\nimport java.sql.Timestamp;\n\npublic class CusDynamicMod {\n\n    private Integer cbrId;\n    private Integer cbrCusIdFrom;\n    private Integer cbrCusIdTo;\n    private Integer cbrBehavior;\n    private Timestamp cbrTime;\n    // 行为发生的位置代号, 0: 默认, 1: 文章, 2: 评论, 3:回复\n    private Integer cbrType;\n    private Integer cbrArtId;\n\n    private Customer cusFrom;\n    private Customer cusTo;\n    private ArtFullMod article;\n    private ComFullMod comment;\n    private RepFullMod reply;\n\n    public Integer getCbrId() {\n        return cbrId;\n    }\n\n    public void setCbrId(Integer cbrId) {\n        this.cbrId = cbrId;\n    }\n\n    public Integer getCbrCusIdFrom() {\n        return cbrCusIdFrom;\n    }\n\n    public void setCbrCusIdFrom(Integer cbrCusIdFrom) {\n        this.cbrCusIdFrom = cbrCusIdFrom;\n    }\n\n    public Integer getCbrCusIdTo() {\n        return cbrCusIdTo;\n    }\n\n    public void setCbrCusIdTo(Integer cbrCusIdTo) {\n        this.cbrCusIdTo = cbrCusIdTo;\n    }\n\n    public Integer getCbrBehavior() {\n        return cbrBehavior;\n    }\n\n    public void setCbrBehavior(Integer cbrBehavior) {\n        this.cbrBehavior = cbrBehavior;\n    }\n\n    public Timestamp getCbrTime() {\n        return cbrTime;\n    }\n\n    public void setCbrTime(Timestamp cbrTime) {\n        this.cbrTime = cbrTime;\n    }\n\n    public Integer getCbrType() {\n        return cbrType;\n    }\n\n    public void setCbrType(Integer cbrType) {\n        this.cbrType = cbrType;\n    }\n\n    public Customer getCusFrom() {\n        return cusFrom;\n    }\n\n    public void setCusFrom(Customer cusFrom) {\n        this.cusFrom = cusFrom;\n    }\n\n    public Customer getCusTo() {\n        return cusTo;\n    }\n\n    public void setCusTo(Customer cusTo) {\n        this.cusTo = cusTo;\n    }\n\n    public ArtFullMod getArticle() {\n        return article;\n    }\n\n    public void setArticle(ArtFullMod article) {\n        this.article = article;\n    }\n\n    public ComFullMod getComment() {\n        return comment;\n    }\n\n    public void setComment(ComFullMod comment) {\n        this.comment = comment;\n    }\n\n    public RepFullMod getReply() {\n        return reply;\n    }\n\n    public void setReply(RepFullMod reply) {\n        this.reply = reply;\n    }\n\n    public Integer getCbrArtId() {\n        return cbrArtId;\n    }\n\n    public void setCbrArtId(Integer cbrArtId) {\n        this.cbrArtId = cbrArtId;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/CusFeatureFullMod.java",
    "content": "package com.smacul.demo.model;\n\nimport com.smacul.demo.bean.CusFeatureCount;\n\npublic class CusFeatureFullMod {\n    private Integer cusId;\n    private Integer readNum;\n    private Integer fanNum;\n    private Integer followNum;\n\n    private Integer artEditNum;\n    private Integer comEditNum;\n    private Integer repEditNum;\n\n    private CusFeatureCount featureCount;\n\n    public Integer getCusId() {\n        return cusId;\n    }\n\n    public void setCusId(Integer cusId) {\n        this.cusId = cusId;\n    }\n\n    public Integer getReadNum() {\n        return readNum;\n    }\n\n    public void setReadNum(Integer readNum) {\n        this.readNum = readNum;\n    }\n\n    public Integer getFanNum() {\n        return fanNum;\n    }\n\n    public void setFanNum(Integer fanNum) {\n        this.fanNum = fanNum;\n    }\n\n    public Integer getFollowNum() {\n        return followNum;\n    }\n\n    public void setFollowNum(Integer followNum) {\n        this.followNum = followNum;\n    }\n\n    public Integer getArtEditNum() {\n        return artEditNum;\n    }\n\n    public void setArtEditNum(Integer artEditNum) {\n        this.artEditNum = artEditNum;\n    }\n\n    public Integer getComEditNum() {\n        return comEditNum;\n    }\n\n    public void setComEditNum(Integer comEditNum) {\n        this.comEditNum = comEditNum;\n    }\n\n    public Integer getRepEditNum() {\n        return repEditNum;\n    }\n\n    public void setRepEditNum(Integer repEditNum) {\n        this.repEditNum = repEditNum;\n    }\n\n    public CusFeatureCount getFeatureCount() {\n        return featureCount;\n    }\n\n    public void setFeatureCount(CusFeatureCount featureCount) {\n        this.featureCount = featureCount;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/model/RepFullMod.java",
    "content": "package com.smacul.demo.model;\n\nimport com.smacul.demo.bean.Customer;\n\nimport java.sql.Timestamp;\n\npublic class RepFullMod {\n\n    private Integer repId;\n    private String repContent;\n\n    private Integer repType;\n    private Timestamp repTime;\n    private Integer repLegal;\n    private String repSpider;\n\n    private Integer repCusId;\n    private Integer repArtId;\n    private Integer repComId;\n    private Integer repRepId;\n\n    private Customer customer;\n\n    public Integer getRepId() {\n        return repId;\n    }\n\n    public void setRepId(Integer repId) {\n        this.repId = repId;\n    }\n\n    public String getRepContent() {\n        return repContent;\n    }\n\n    public void setRepContent(String repContent) {\n        this.repContent = repContent;\n    }\n\n    public Integer getRepType() {\n        return repType;\n    }\n\n    public void setRepType(Integer repType) {\n        this.repType = repType;\n    }\n\n    public Timestamp getRepTime() {\n        return repTime;\n    }\n\n    public void setRepTime(Timestamp repTime) {\n        this.repTime = repTime;\n    }\n\n    public Integer getRepLegal() {\n        return repLegal;\n    }\n\n    public void setRepLegal(Integer repLegal) {\n        this.repLegal = repLegal;\n    }\n\n    public String getRepSpider() {\n        return repSpider;\n    }\n\n    public void setRepSpider(String repSpider) {\n        this.repSpider = repSpider;\n    }\n\n    public Integer getRepCusId() {\n        return repCusId;\n    }\n\n    public void setRepCusId(Integer repCusId) {\n        this.repCusId = repCusId;\n    }\n\n    public Integer getRepArtId() {\n        return repArtId;\n    }\n\n    public void setRepArtId(Integer repArtId) {\n        this.repArtId = repArtId;\n    }\n\n    public Integer getRepComId() {\n        return repComId;\n    }\n\n    public void setRepComId(Integer repComId) {\n        this.repComId = repComId;\n    }\n\n    public Integer getRepRepId() {\n        return repRepId;\n    }\n\n    public void setRepRepId(Integer repRepId) {\n        this.repRepId = repRepId;\n    }\n\n    public Customer getCustomer() {\n        return customer;\n    }\n\n    public void setCustomer(Customer customer) {\n        this.customer = customer;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/DiscussService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.bean.Comment;\nimport com.smacul.demo.bean.Reply;\nimport com.smacul.demo.model.ComFullMod;\nimport org.springframework.web.bind.annotation.RequestBody;\n\nimport java.util.List;\n\npublic interface DiscussService {\n\n    /**\n     * 获取完整的评论列表\n     * 20-04-20 创建方法\n     * @param artId\n     * @return\n     */\n    List<ComFullMod> getComList(Integer artId);\n\n    /**\n     * 添加评论\n     * 20-04-20 创建方法\n     * @param comment\n     * @return\n     */\n    String addNewCom(Comment comment);\n\n    /**\n     * 添加回复, 包括回复的回复\n     * 20-04-20 创建方法\n     * @param reply\n     * @return\n     */\n    String addNewRep(Reply reply);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/EditService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.bean.Article;\n\npublic interface EditService {\n\n    /**\n     * 用户添加新文章\n     * 20-05-04 创建方法\n     * 20-05-11 方法修改, 添加 artLegal\n     * @param article\n     * @return\n     */\n    String addNewArt(Article article);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/LoadService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.model.ArtFullMod;\n\nimport java.util.List;\n\npublic interface LoadService {\n\n    /**\n     * 为新用户提供文章类别列表\n     * 20-04-18 创建方法\n     * @return\n     */\n    List<String> getArtTypesForNew();\n\n    /**\n     * 为老用户提供文章类别列表\n     * 20-04-19 创建方法, TODO 功能上和 getArtTypesForNew 没有区别, 需要跟换\n     * @param cusId\n     * @return\n     */\n    List<String> getArtTypesForOld(Integer cusId);\n\n    /**\n     * 为新用户提供一页指定类别的新闻缩率信息\n     * 20-04-19 创建方法\n     * 20-04-28 方法修改, 添加用户浏览内容去重\n     * 20-05-06 方法修改, 返回时将文章类别从英文翻译成中文\n     * 20-05-13 修改文章推荐方式, 核心文章 pageSize-3: 资讯文章 2: 新生文章 1\n     * 20-05-24 方法修改, artType 接受英文\n     * @param artType\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyArtOnePageByTypeForNew(Integer cusId, String artType, Integer page, Integer pageSize);\n\n    /**\n     * 为老用户提供一页指定类别的新闻缩率信息\n     * 如果相似用户的内容推荐完毕, 就切换到新用户的推荐逻辑上.\n     * 20-04-19 创建方法\n     * 20-04-28 方法修改, 添加用户浏览内容去重\n     * 20-05-02 添加对老用户的推荐\n     * 20-05-06 方法修改, 返回时将文章类别从英文翻译成中文\n     * 20-05-13 修改文章推荐方式, 协同推荐文章 pageSize-1: 新生文章 1\n     * 20-05-19 方法修改, 当相似用户推荐低于 10 的时候, 返回长度为 0 的列表\n     * 20-05-24 方法修改, artType 接受英文\n     * @param artType\n     * @param cusList   相似用户列表\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getTinyArtOnePageByTypeForOld(\n            Integer cusId, List<Integer> cusList, String artType, Integer page, Integer pageSize);\n\n    /**\n     * 提供一页的热点新闻的缩略信息\n     * 20-04-19 创建方法\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> getHotArtOnePage(Integer page, Integer pageSize);\n\n    /**\n     * 获取一篇文章的完整信息, 包括文章, 文章作者, 文章特征统计数据, 当前用户与文章的关系\n     * 20-04-19 创建方法\n     * 20-05-06 修改方法, 获取文章时返回文章的中文类别\n     * @param cusId\n     * @param artId\n     * @return\n     */\n    ArtFullMod getFullArt(Integer cusId, Integer artId);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/SearchService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.model.ArtFullMod;\n\nimport java.util.List;\n\npublic interface SearchService {\n\n    /**\n     * 简单的搜索 % %\n     * 20-04-20 创建方法\n     * 20-05-06\n     * @param key\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    List<ArtFullMod> searchContentSimple(String key, Integer page, Integer pageSize);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/SelfService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.model.CusDynamicMod;\nimport com.smacul.demo.model.CusFeatureFullMod;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.List;\n\npublic interface SelfService {\n\n    /**\n     * 检查用户是否为新用户.\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    Boolean checkIsNewUser(Integer cusId);\n\n    /**\n     * 在用户登录时检查用户是否存在, 如果存在, 返回用户基本信息, 否则返回空.\n     * 20-04-28 创建方法\n     * @param cusName\n     * @param cusPass\n     * @return\n     * @throws NoSuchAlgorithmException\n     */\n    Customer checkCusForLogin(String cusName, String cusPass) throws NoSuchAlgorithmException;\n\n    /**\n     * 在用户注册时插入用户.\n     * 20-04-18 创建方法\n     * 20-04-23 方法逻辑修改, 在添加用户时, 添加用户的特征统计数据记录.\n     * @param cusName\n     * @param cusPass\n     * @return\n     * @throws NoSuchAlgorithmException\n     */\n    String setNewCus(String cusName, String cusPass) throws NoSuchAlgorithmException;\n\n    /**\n     * 获取用户基本数据, 不包括密码\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    Customer getCusBasicInfo(Integer cusId);\n\n    /**\n     * 设置用户基本数据, 可包括密码\n     * 20-04-18 创建方法\n     * @param customer\n     * @return\n     * @throws NoSuchAlgorithmException\n     */\n    Boolean setCusBasicInfo(Customer customer) throws NoSuchAlgorithmException;\n\n    /**\n     * 处理用户关注, 行为代码: 11\n     * 20-04-18 创建方法\n     * 20-04-26 修改方法, 只有当用户关注关系创建时, 才返回 true.\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Boolean setCusFollow(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 获取用户完整的特征数据\n     * 20-04-18 创建方法\n     * @param cusId\n     * @return\n     */\n    CusFeatureFullMod getCusFeatureInfo(Integer cusId);\n\n    /**\n     * 分页获取指定用户的动态\n     * 20-04-24 创建方法\n     * 20-05-06 修改方法, 用户动态如果有文章, 则将文章的类别由英文改为中文\n     * @param cusId\n     * @param page\n     * @param pageSize\n     * @return\n     */\n    List<CusDynamicMod> getCusDynamic(Integer cusId, Integer page, Integer pageSize);\n\n    /**\n     * 检查用户之间是否存在关注关系\n     * 20-04-26 创建方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Boolean checkCusFollow(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 获取指定用户的相似用户\n     * 如果用户是新用户则不计算相似用户, 直接返回空的 ArrayList;\n     * 如果用户是老用户, 优先考虑他关注的用户, 再计算相似用户.\n     * 返回 10 个吧先\n     * 20-05-02 创建方法\n     * 20-05-19 删除关注用户的添加逻辑\n     * @param cusId\n     * @param num\n     * @return\n     */\n    List<Integer> getRelativeCusList(Integer cusId, Integer num);\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/SessionService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.bean.Customer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpSession;\nimport java.util.List;\n\npublic interface SessionService {\n\n    void setCusSession(Customer cus);\n\n    void setRelSession(List<Integer> rel);\n\n    Customer getCusSession();\n\n    List<Integer> getRelSession();\n\n    Integer getPagThenAddOne(String category);\n\n    Integer getSetPagAfterCusChange(String category);\n\n    void initPagSession();\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/ShapeService.java",
    "content": "package com.smacul.demo.service;\n\nimport com.smacul.demo.model.ArtFullMod;\nimport com.sun.org.apache.xpath.internal.operations.Bool;\n\nimport java.util.List;\n\npublic interface ShapeService {\n\n    /**\n     * 文章编辑 1\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     |    cusId   |       1     |   artTime   |   artId  |    1    |     artId\n     * 20-04-19 创建方法\n     * @param cusId\n     * @param artId\n     * @return\n     */\n    Boolean setCusBehaviorArtEdit(Integer cusId, Integer artId);\n\n    /**\n     * 文章阅读 2\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     |  artCusId  |       2     |   readTime  |   artId  |    1    |     artId\n     * 20-04-19 创建方法\n     * 20-04-28 修改方法, 防止同一个用户重复阅读\n     * @param cusId\n     * @param artId\n     * @return\n     */\n    Boolean setCusBehaviorArtRead(Integer cusId, Integer artId);\n\n    /**\n     * 文章点赞 3\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     |  artCusId  |       3     |   likeTime  |   artId  |    1    |     artId\n     * 20-04-19 创建方法\n     * @param cusId\n     * @param artId\n     * @param type  true: 点上, false: 取消\n     * @return\n     */\n    Boolean setCusBehaviorArtLike(Integer cusId, Integer artId, Boolean type);\n\n    /**\n     * 文章点踩 4\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     |  artCusId  |       4     | dislikeTime |   artId  |    1    |     artId\n     * 20-04-19 创建方法\n     * @param cusId\n     * @param artId\n     * @param type  true: 点上, false: 取消\n     * @return\n     */\n    Boolean setCusBehaviorArtDislike(Integer cusId, Integer artId, Boolean type);\n\n    /**\n     * 评论编辑 5\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     | artCusId   |       5     |   comTime   |   artId  |    2    |     comId\n     * @param cusId\n     * @param artId\n     * @param comId\n     * @return\n     */\n    Boolean setCusBehaviorComEdit(Integer cusId, Integer artId, Integer comId);\n\n    /**\n     * 评论点赞 6\n     * @param cusId\n     * @param comCusId\n     * @param artId\n     * @param comId\n     * @return\n     */\n    Boolean setCusBehaviorComLike(Integer cusId, Integer comCusId, Integer artId, Integer comId);\n\n    /**\n     * 评论点踩 7\n     * @param cusId\n     * @param comCusId\n     * @param artId\n     * @param comId\n     * @return\n     */\n    Boolean setCusBehaviorComDislike(Integer cusId, Integer comCusId, Integer artId, Integer comId);\n\n    /**\n     * 回复编辑(包括回复与回复的回复) 8\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *    cusId     | artCusId   |       8     |   repTime   |   artId  |    3    |     repId\n     * 20-04-19 创建方法\n     * @param cusId\n     * @param artId\n     * @param repId\n     * @return\n     */\n    Boolean setCusBehaviorRepEdit(Integer cusId, Integer artId, Integer repId);\n\n    /**\n     * 回复点赞 9\n     * @param cusId\n     * @param repCusId\n     * @param artId\n     * @param repId\n     * @return\n     */\n    Boolean setCusBehaviorRepLike(Integer cusId, Integer repCusId, Integer artId, Integer repId);\n\n    /**\n     * 回复点踩 10\n     * @param cusId\n     * @param repCusId\n     * @param artId\n     * @param repId\n     * @return\n     */\n    Boolean setCusBehaviorRepDislike(Integer cusId, Integer repCusId, Integer artId, Integer repId);\n\n    /**\n     * 用户 follow 11\n     * cbrCusIdFrom | cbrCusIdTo | cbrBehavior |   cbrTime   | cbrArtId | cbrType | cbrTargetId\n     *   cusIdFrom  |   cusIdTo  |      11     | followTime  |    null  |    0    |     null\n     * 20-04-19 创建方法\n     * @param cusIdFrom\n     * @param cusIdTo\n     * @return\n     */\n    Boolean setCusBehaviorCusFollow(Integer cusIdFrom, Integer cusIdTo);\n\n    /**\n     * 记录系统推荐内容, 并删除指定用户历史 72 小时的推荐内容\n     * 20-06-03\n     * @param list\n     * @return\n     */\n    Boolean recordRecommendList(Integer cusId, List<ArtFullMod> list);\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/DiscussServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.bean.Comment;\nimport com.smacul.demo.bean.Reply;\nimport com.smacul.demo.dao.ComDao;\nimport com.smacul.demo.dao.RepDao;\nimport com.smacul.demo.model.ComFullMod;\nimport com.smacul.demo.service.DiscussService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n@Service\npublic class DiscussServiceImpl implements DiscussService {\n\n    @Autowired\n    ComDao comDao;\n    @Autowired\n    RepDao repDao;\n\n    @Override\n    public List<ComFullMod> getComList(Integer artId) {\n        return comDao.getComFullList(artId);\n    }\n\n    @Override\n    public String addNewCom(Comment comment) {\n        if (comDao.addCom(comment) == 1) {\n            return \"评论成功\";\n        } else {\n            return \"评论失败\";\n        }\n    }\n\n    @Override\n    public String addNewRep(Reply reply) {\n        if (repDao.addRep(reply) == 1) {\n            return \"评论成功\";\n        } else {\n            return \"评论失败\";\n        }\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/EditServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.bean.Article;\nimport com.smacul.demo.dao.ArtDao;\nimport com.smacul.demo.service.EditService;\nimport com.smacul.demo.util.TypeHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class EditServiceImpl implements EditService {\n\n    @Autowired\n    ArtDao artDao;\n\n    @Override\n    public String addNewArt(Article article) {\n        String type = article.getArtType();\n        article.setArtType(TypeHandler.typeTransSingleChToEn(type));\n        article.setArtLegal(1);\n        if (artDao.addArt(article) == 1) {\n            return \"文章添加成功\";\n        } else {\n            return \"文章添加失败\";\n        }\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/LoadServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.dao.ArtDao;\nimport com.smacul.demo.dao.ArtFeatureCountDao;\nimport com.smacul.demo.dao.CusBehaviorRecordDao;\nimport com.smacul.demo.dao.CusFeatureCountDao;\nimport com.smacul.demo.model.ArtFullMod;\nimport com.smacul.demo.model.CusArtBehaviorMod;\nimport com.smacul.demo.service.LoadService;\nimport com.smacul.demo.util.PageHandler;\nimport com.smacul.demo.util.TypeHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.swing.*;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.TransferQueue;\n\n@Service\npublic class LoadServiceImpl implements LoadService {\n\n    @Autowired\n    ArtDao artDao;\n    @Autowired\n    CusFeatureCountDao cusFeatureCountDao;\n    @Autowired\n    ArtFeatureCountDao artFeatureCountDao;\n    @Autowired\n    CusBehaviorRecordDao cusBehaviorRecordDao;\n\n    @Override\n    public List<String> getArtTypesForNew() {\n        List<String> result = artDao.getArtTypesOrderByTypeNum();\n        return TypeHandler.typeTransAllEnToCh(result);\n    }\n\n    @Override\n    public List<String> getArtTypesForOld(Integer cusId) {\n        List<String> result = artDao.getArtTypesOrderByTypeNum();\n        return TypeHandler.typeTransAllEnToCh(result);\n    }\n\n    @Override\n    public List<ArtFullMod> getTinyArtOnePageByTypeForNew(\n            Integer cusId, String artType, Integer page, Integer pageSize) {\n        Integer start = PageHandler.calcuStartNO(page, pageSize);\n        List<ArtFullMod> resultList = null;\n        if (artType.equals(\"news_global\")) {\n            resultList = artDao.getTinyInfoArtFromGlobalForNew(cusId, start, 2);\n            resultList.addAll(artDao.getTinyHotArtFromGlobalForNew(cusId, start, pageSize-1-2));\n            resultList.addAll(artDao.getTinyNewArtFromGlobalForNew(cusId, start, 1));\n        } else {\n            resultList = artDao.getTinyNewArtByTypeForNew(artType, cusId, start, 1);\n            resultList.addAll(artDao.getTinyArtOnePageByTypeNew(artType, cusId, start, pageSize-1));\n        }\n        for (ArtFullMod result: resultList) {\n            result.setArtType(TypeHandler.typeTransSingleEnToCh(result.getArtType()));\n        }\n        return resultList;\n    }\n\n    @Override\n    public List<ArtFullMod> getTinyArtOnePageByTypeForOld(\n            Integer cusId, List<Integer> cusList, String artType, Integer page, Integer pageSize) {\n        Integer start = PageHandler.calcuStartNO(page, pageSize);\n        String cusIdListStr = \"\";\n        for (int i = 0; i < cusList.size(); i++) {\n            if (i != (cusList.size() - 1)) {\n                cusIdListStr += cusList.get(i) + \", \";\n            } else {\n                cusIdListStr += cusList.get(i);\n            }\n        }\n        List<ArtFullMod> resultList = null;\n        if (artType.equals(\"news_global\")) {\n            resultList = artDao.getTinyHotArtFromGlobalForNew(cusId, start, 3);\n            resultList.addAll(artDao.getTinyArtOnePageFromGlobalOld(cusId, cusIdListStr, start, pageSize-1-3));\n            resultList.addAll(artDao.getTinyNewArtFromGlobalForOld(cusId, start, 1));\n        } else {\n            resultList = artDao.getTinyArtOnePageByTypeOld(artType, cusId, cusIdListStr, start, pageSize-1);\n            resultList.addAll(artDao.getTinyNewArtByTypeForOld(artType, cusId, start, 1));\n        }\n        // 如果相似用户的推荐内容数量不足 10, 则返回长度为 0 的列表.\n        if (resultList.size() < 10) {\n            return new ArrayList<>();\n        } else {\n            for (ArtFullMod result: resultList) {\n                result.setArtType(TypeHandler.typeTransSingleEnToCh(result.getArtType()));\n            }\n            return resultList;\n        }\n    }\n\n    @Override\n    public List<ArtFullMod> getHotArtOnePage(Integer page, Integer pageSize) {\n        Integer start = PageHandler.calcuStartNO(page, pageSize);\n        //if (page <= 4) {\n        //    start = PageHandler.calcuStartNO(page, pageSize);\n        //}\n        return artDao.getHotArtOnePage(start, pageSize);\n    }\n\n    @Override\n    public ArtFullMod getFullArt(Integer cusId, Integer artId) {\n        ArtFullMod artFullMod = artDao.getArtFull(artId);\n        artFullMod.setArtType(TypeHandler.typeTransSingleEnToCh(artFullMod.getArtType()));\n        CusArtBehaviorMod behaviorMod = new CusArtBehaviorMod();\n        behaviorMod.setArtId(artId);\n        behaviorMod.setCusId(cusId);\n        // 是否阅读过此文章\n        if (cusBehaviorRecordDao.countTargetCusArtBehaviorFrom(cusId, artId, 2) >= 1) {\n            behaviorMod.setRead(true);\n        } else {\n            behaviorMod.setRead(false);\n        }\n        // 是否点赞\n        if (cusBehaviorRecordDao.countTargetCusArtBehaviorFrom(cusId, artId, 3) == 1) {\n            behaviorMod.setPreference(1);\n        } else if (cusBehaviorRecordDao.countTargetCusArtBehaviorFrom(cusId, artId, 4) == 1) {\n            behaviorMod.setPreference(-1);\n        } else {\n            behaviorMod.setPreference(0);\n        }\n        // 是否是文章作者\n        if (cusBehaviorRecordDao.countTargetCusArtBehaviorFrom(cusId, artId, 1) == 1) {\n            behaviorMod.setArtAuthor(true);\n        } else {\n            behaviorMod.setArtAuthor(false);\n        }\n        // 是否关注了文章作者\n        if (cusBehaviorRecordDao.countTargetCusFollowBehavior(cusId, artFullMod.getArtCusId()) == 1) {\n            behaviorMod.setFollow(true);\n        } else {\n            behaviorMod.setRead(false);\n        }\n        artFullMod.setCusArtBehavior(behaviorMod);\n        return artFullMod;\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/SearchServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.dao.ArtDao;\nimport com.smacul.demo.model.ArtFullMod;\nimport com.smacul.demo.service.SearchService;\nimport com.smacul.demo.util.PageHandler;\nimport com.smacul.demo.util.TypeHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n@Service\npublic class SearchServiceImpl implements SearchService {\n\n    @Autowired\n    ArtDao artDao;\n\n    @Override\n    public List<ArtFullMod> searchContentSimple(String key, Integer page, Integer pageSize) {\n        Integer start = PageHandler.calcuStartNO(page, pageSize);\n        List<ArtFullMod> resultList = artDao.searchContentSimple(key, start, pageSize);\n        for (ArtFullMod result: resultList) {\n            result.setArtType(TypeHandler.typeTransSingleEnToCh(result.getArtType()));\n        }\n        return resultList;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/SelfServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.bean.CusBehaviorRecord;\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.dao.CusBehaviorRecordDao;\nimport com.smacul.demo.dao.CusDao;\nimport com.smacul.demo.dao.CusFeatureCountDao;\nimport com.smacul.demo.model.CusDynamicMod;\nimport com.smacul.demo.model.CusFeatureFullMod;\nimport com.smacul.demo.service.SelfService;\nimport com.smacul.demo.util.MD5;\nimport com.smacul.demo.util.PageHandler;\nimport com.smacul.demo.util.TypeHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Service\npublic class SelfServiceImpl implements SelfService {\n\n    @Autowired\n    CusDao cusDao;\n    @Autowired\n    CusFeatureCountDao cusFeatureCountDao;\n    @Autowired\n    CusBehaviorRecordDao cusBehaviorRecordDao;\n\n    @Override\n    public Boolean checkIsNewUser(Integer cusId) {\n        Integer behaviorNum = cusFeatureCountDao.countBehaviorNum(cusId);\n        if (behaviorNum > 20) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    @Override\n    public Customer checkCusForLogin(String cusName, String cusPass) throws NoSuchAlgorithmException {\n        String cryptString = MD5.MD5Creator(cusPass);\n        Customer customer = cusDao.getCusByName(cusName);\n        if (customer != null && cryptString.equals(customer.getCusPass())) {\n            return customer;\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public String setNewCus(String cusName, String cusPass) throws NoSuchAlgorithmException {\n        String cryptString = MD5.MD5Creator(cusPass);\n        if (cusDao.countCusByName(cusName) != 0) {\n            return \"当前用户名已被注册\";\n        }\n        Integer cusResult = cusDao.insertCusForRegister(cusName, cryptString);\n        Customer customer = cusDao.getCusByName(cusName);\n        Integer cusFeature = 0;\n        if (customer != null) {\n            cusFeature = cusFeatureCountDao.initialCusFeature(customer.getCusId());\n        }\n        if (cusResult == 1 && cusFeature == 1) {\n            return \"注册成功\";\n        } else {\n            return \"注册失败\";\n        }\n    }\n\n    @Override\n    public Customer getCusBasicInfo(Integer cusId) {\n        Customer customer = cusDao.getCusById(cusId);\n        customer.setCusPass(null);\n        return customer;\n    }\n\n    @Override\n    public Boolean setCusBasicInfo(Customer customer) throws NoSuchAlgorithmException {\n        if (customer.getCusPass() == null) {\n            if (cusDao.updateCusBasicInfoWithPass(customer) == 1) {\n                return true;\n            }\n        } else {\n            customer.setCusPass(MD5.MD5Creator(customer.getCusPass()));\n            if (cusDao.updateCusBasicInfo(customer) == 1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public Boolean setCusFollow(Integer cusIdFrom, Integer cusIdTo) {\n        if (cusBehaviorRecordDao.countTargetCusFollowBehavior(cusIdFrom, cusIdTo) == 1) {\n            if (cusBehaviorRecordDao.deleteTargetCusFollowBehavior(cusIdFrom, cusIdTo) == 1) {\n                return false;\n            }\n        } else {\n            if (cusBehaviorRecordDao.addTargetCusFollowBehavior(cusIdFrom, cusIdTo) == 1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public CusFeatureFullMod getCusFeatureInfo(Integer cusId) {\n        CusFeatureFullMod cusFeatureFullMod = new CusFeatureFullMod();\n        cusFeatureFullMod.setCusId(cusId);\n        cusFeatureFullMod.setReadNum(cusBehaviorRecordDao.countCusBehaviorFrom(cusId, 2));\n        cusFeatureFullMod.setFanNum(cusBehaviorRecordDao.countCusBehaviorTo(cusId, 11));\n        cusFeatureFullMod.setFollowNum(cusBehaviorRecordDao.countCusBehaviorFrom(cusId, 11));\n        cusFeatureFullMod.setArtEditNum(cusBehaviorRecordDao.countCusBehaviorFrom(cusId, 1));\n        cusFeatureFullMod.setComEditNum(cusBehaviorRecordDao.countCusBehaviorFrom(cusId, 5));\n        cusFeatureFullMod.setRepEditNum(cusBehaviorRecordDao.countCusBehaviorFrom(cusId, 8));\n        cusFeatureFullMod.setFeatureCount(cusFeatureCountDao.getCusFeatureCountByCusId(cusId));\n        return cusFeatureFullMod;\n    }\n\n    @Override\n    public List<CusDynamicMod> getCusDynamic(Integer cusId, Integer page, Integer pageSize) {\n        Integer start = PageHandler.calcuStartNO(page, pageSize);\n        List<CusDynamicMod> resultList = cusBehaviorRecordDao.getCusDynamicByCusId(cusId, start, pageSize);\n        for (CusDynamicMod result: resultList) {\n            if (result.getCbrType() != 0) {\n                result.getArticle().setArtType(TypeHandler.typeTransSingleEnToCh(result.getArticle().getArtType()));\n            }\n        }\n        return resultList;\n    }\n\n    @Override\n    public Boolean checkCusFollow(Integer cusIdFrom, Integer cusIdTo) {\n        if (cusBehaviorRecordDao.countTargetCusFollowBehavior(cusIdFrom, cusIdTo) == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public List<Integer> getRelativeCusList(Integer cusId, Integer num) {\n        // 判断用户类型\n        if (checkIsNewUser(cusId)) {\n            return new ArrayList<>();\n        }\n        // 是老用户获取关注用户\n        //List<Integer> followCusList = cusBehaviorRecordDao.getFollowCus(cusId);\n        //if (followCusList.size() >= 10) {\n        //    return followCusList.subList(0, 10);\n        //}\n        // 是老用户获取相似用户\n        //Integer leftNum = num - followCusList.size();\n        Integer leftNum = 10;\n        List<Integer> followCusList = cusFeatureCountDao.getRelativeCusList(cusId, leftNum);\n        return followCusList;\n    }\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/SessionServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.service.SessionService;\nimport com.smacul.demo.util.PageHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.servlet.http.HttpSession;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\n@Service\npublic class SessionServiceImpl implements SessionService {\n\n    @Autowired\n    HttpSession session;\n\n    private static final String CUS = \"customer\";\n    private static final String REL = \"relative\";\n    private static final String PAG = \"pages\";\n\n    @Override\n    public void setCusSession(Customer cus) {\n        session.setAttribute(CUS, cus);\n    }\n\n    @Override\n    public void setRelSession(List<Integer> rel) {\n        session.setAttribute(REL, rel);\n    }\n\n    @Override\n    public Customer getCusSession() {\n        return (Customer) session.getAttribute(CUS);\n    }\n\n    @Override\n    public List<Integer> getRelSession() {\n        return (List<Integer>) session.getAttribute(REL);\n    }\n\n    @Override\n    public void initPagSession() {\n        session.setAttribute(PAG, PageHandler.initPageList());\n    }\n\n    @Override\n    public Integer getPagThenAddOne(String category) {\n        Map<String, Integer> pages = (Map<String, Integer>)session.getAttribute(PAG);\n        Integer pag = 0;\n        if (category.equals(\"news_hot\")) {\n            pag = pages.get(\"news_hot\");\n            if (pag > 4) {\n                pages.replace(\"news_hot\", 0);\n            } else {\n                pages.replace(\"news_hot\", pag+1);\n            }\n        } else {\n            pag = pages.get(category);\n            pages.replace(category, pag+1);\n        }\n        session.setAttribute(PAG, pages);\n        return pag;\n    }\n\n    @Override\n    public Integer getSetPagAfterCusChange(String category) {\n        Map<String, Integer> pages = (Map<String, Integer>)session.getAttribute(PAG);\n        pages.replace(category, 0);\n        session.setAttribute(PAG, pages);\n        return 0;\n    }\n\n    //public void setSession(String name, Object object) {\n    //    switch (name) {\n    //        case CUS:\n    //            session.setAttribute(CUS, object);\n    //            break;\n    //        case REL:\n    //            session.setAttribute(REL, object);\n    //            break ;\n    //\n    //    }\n    //}\n    //\n    //public Object getSession(String name) {\n    //    switch (name) {\n    //        case CUS:\n    //            session.getAttribute(CUS);\n    //            break;\n    //        case REL:\n    //            session.getAttribute(REL);\n    //            break ;\n    //    }\n    //}\n    //\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/service/impl/ShapeServiceImpl.java",
    "content": "package com.smacul.demo.service.impl;\n\nimport com.smacul.demo.bean.Customer;\nimport com.smacul.demo.dao.*;\nimport com.smacul.demo.model.ArtFullMod;\nimport com.smacul.demo.service.ShapeService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Service\npublic class ShapeServiceImpl implements ShapeService {\n\n    @Autowired\n    ArtDao artDao;\n    @Autowired\n    CusBehaviorRecordDao cbrDao;\n    @Autowired\n    CusFeatureCountDao cusFeatureCountDao;\n    @Autowired\n    ArtFeatureCountDao artFeatureCountDao;\n    @Autowired\n    CusRecommendRecordDao cusRecommendRecordDao;\n\n    @Override\n    public Boolean setCusBehaviorArtEdit(Integer cusId, Integer artId) {\n        String artType = artDao.getArtTypeByArtId(artId);\n        Integer cbr = cbrDao.addCusBehavior(cusId, cusId, 1, artId, 1, artId);\n        Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, 1);\n        if (cbr == 1 && cfc == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public Boolean setCusBehaviorArtRead(Integer cusId, Integer artId) {\n        String artType = artDao.getArtTypeByArtId(artId);\n        Integer artCusId = artDao.getArtCusIdByArtId(artId);\n        Integer cbr = 0;\n        Integer cfc = 0;\n        Integer afc = 0;\n        Integer readNum = cbrDao.countTargetCusArtBehaviorFrom(cusId, artId, 2);\n        if (readNum < 1) {\n            cbr = cbrDao.addCusBehavior(cusId, artCusId, 2, artId, 1, artId);\n            cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, 1);\n            afc = artFeatureCountDao.updateArtFeature(artId, \"afc_read_num\", 1);\n        }\n        if (readNum >=1 || (cbr == 1 && cfc == 1 && afc == 1)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public Boolean setCusBehaviorArtLike(Integer cusId, Integer artId, Boolean type) {\n        String artType = artDao.getArtTypeByArtId(artId);\n        Integer artCusId = artDao.getArtCusIdByArtId(artId);\n        if (type) {\n            Integer cbr = cbrDao.addCusBehavior(cusId, artCusId, 3, artId, 1, artId);\n            Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, 1);\n            Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_like_num\", 1);\n            if (cbr == 1 && cfc == 1 && afc == 1) {\n                return true;\n            }\n        } else {\n            Integer cbr = cbrDao.deleteCusBehavior(cusId, artCusId, 3, artId, 1, artId);\n            Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, -1);\n            Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_like_num\", -1);\n            if (cbr == 1 && cfc == 1 && afc == 1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public Boolean setCusBehaviorArtDislike(Integer cusId, Integer artId, Boolean type) {\n        String artType = artDao.getArtTypeByArtId(artId);\n        Integer artCusId = artDao.getArtCusIdByArtId(artId);\n        if (type) {\n            Integer cbr = cbrDao.addCusBehavior(cusId, artCusId, 4, artId, 1, artId);\n            Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, 1);\n            Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_dislike_num\", 1);\n            if (cbr == 1 && cfc == 1 && afc == 1) {\n                return true;\n            }\n        } else {\n            Integer cbr = cbrDao.deleteCusBehavior(cusId, artCusId, 4, artId, 1, artId);\n            Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artType, -1);\n            Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_dislike_num\", -1);\n            if (cbr == 1 && cfc == 1 && afc == 1) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public Boolean setCusBehaviorComEdit(Integer cusId, Integer artId, Integer comId) {\n        ArtFullMod artFull = artDao.getArtFull(artId);\n        Integer cbr = cbrDao.addCusBehavior(cusId, artFull.getArtCusId(), 5, artId, 2, comId);\n        Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artFull.getArtType(), 1);\n        Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_com_num\", 1);\n        if (cbr == 1 && cfc == 1 && afc == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public Boolean setCusBehaviorComLike(Integer cusId, Integer comCusId, Integer artId, Integer comId) {\n        return null;\n    }\n\n    @Override\n    public Boolean setCusBehaviorComDislike(Integer cusId, Integer comCusId, Integer artId, Integer comId) {\n        return null;\n    }\n\n    @Override\n    public Boolean setCusBehaviorRepEdit(Integer cusId, Integer artId, Integer repId) {\n        ArtFullMod artFull = artDao.getArtFull(artId);\n        Integer cbr = cbrDao.addCusBehavior(cusId, artFull.getArtCusId(), 8, artId, 3, repId);\n        Integer cfc = cusFeatureCountDao.updateCusFeature(cusId, \"cfc_\" + artFull.getArtType(), 1);\n        Integer afc = artFeatureCountDao.updateArtFeature(artId, \"afc_rep_num\", 1);\n        if (cbr == 1 && cfc == 1 && afc == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public Boolean setCusBehaviorRepLike(Integer cusId, Integer repCusId, Integer artId, Integer repId) {\n        return null;\n    }\n\n    @Override\n    public Boolean setCusBehaviorRepDislike(Integer cusId, Integer repCusId, Integer artId, Integer repId) {\n        return null;\n    }\n\n    @Override\n    public Boolean setCusBehaviorCusFollow(Integer cusIdFrom, Integer cusIdTo) {\n        if (cbrDao.addCusBehavior(cusIdFrom, cusIdTo, 9, null, 0, null) == 1) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    @Override\n    public Boolean recordRecommendList(Integer cusId, List<ArtFullMod> list) {\n        List<Integer> idList = new ArrayList<>();\n        for (ArtFullMod tar: list) {\n            idList.add(tar.getArtId());\n        }\n        cusRecommendRecordDao.deleteOldCommentList(cusId);\n        cusRecommendRecordDao.addRecommendList(cusId, idList);\n        return null;\n    }\n\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/util/MD5.java",
    "content": "package com.smacul.demo.util;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\npublic class MD5 {\n\n    public static String MD5Creator(String plainString) throws NoSuchAlgorithmException {\n        MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n        byte b[] = md5.digest(plainString.getBytes());\n        int i;\n        StringBuffer buf = new StringBuffer(\"\");\n        for(int offset = 0; offset < b.length; offset ++){\n            i = b[offset];\n            if(i < 0){\n                i += 256;\n            }\n            if(i < 16){\n                buf.append(\"0\");\n            }\n            buf.append(Integer.toHexString(i));\n        }\n\n        return buf.toString();\n    }\n\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/util/PageHandler.java",
    "content": "package com.smacul.demo.util;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class PageHandler {\n\n    public static Integer calcuStartNO(Integer page, Integer pageSize) {\n        return page * pageSize;\n    }\n\n    public static Map<String, Integer> initPageList() {\n        Map<String, Integer> pages = new HashMap<>();\n        pages.put(\"news_global\", 0);\n        pages.put(\"news_hot\", 0);\n\n        pages.put(\"news_society\", 0);\n        pages.put(\"news_entertainment\", 0);\n        pages.put(\"news_tech\", 0);\n        pages.put(\"news_military\", 0);\n        pages.put(\"news_sports\", 0);\n        pages.put(\"news_car\", 0);\n\n        pages.put(\"news_finance\", 0);\n        pages.put(\"news_world\", 0);\n        pages.put(\"news_fashion\", 0);\n        pages.put(\"news_travel\", 0);\n        pages.put(\"news_discovery\", 0);\n        pages.put(\"news_baby\", 0);\n\n        pages.put(\"news_regimen\", 0);\n        pages.put(\"news_story\", 0);\n        pages.put(\"news_essay\", 0);\n        pages.put(\"news_game\", 0);\n        pages.put(\"news_history\", 0);\n        pages.put(\"news_food\", 0);\n\n        return pages;\n    }\n\n    //public static void hotArtPageCheck(Map<String, Integer> pages) {\n    //    if (pages.get(\"hot\") > 4) {\n    //        pages.replace(\"hot\", 0);\n    //    }\n    //}\n    //\n    //public static void pageChange(Map<String, Integer> pages, String category, Integer num) {\n    //    pages.replace(category, num);\n    //}\n}\n"
  },
  {
    "path": "back/src/main/java/com/smacul/demo/util/TypeHandler.java",
    "content": "package com.smacul.demo.util;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class TypeHandler {\n\n    private static final String[] ch = {\"综合\", \"社会\", \"娱乐\", \"科技\", \"军事\", \"体育\", \"汽车\", \"财经\", \"国际\", \"时尚\", \"旅游\", \"探索\",\n            \"育儿\", \"养生\", \"故事\", \"美文\", \"游戏\", \"历史\", \"美食\"};\n    private static final String[] en = {\"news_global\", \"news_society\", \"news_entertainment\", \"news_tech\", \"news_military\", \"news_sports\",\n            \"news_car\", \"news_finance\", \"news_world\", \"news_fashion\", \"news_travel\",\n            \"news_discovery\", \"news_baby\", \"news_regimen\", \"news_story\", \"news_essay\",\n            \"news_game\", \"news_history\", \"news_food\"};\n\n    //public static List<String> sortTypeEn(List<Integer> nums) {\n    //    Map<String, Integer> dictionary = new HashMap<>();\n    //    for (int i = 0; i < nums.size(); i++) {\n    //        dictionary.put(en[i+1], nums.get(i));\n    //    }\n    //\n    //}\n\n    //public static List<String> sortTypeCh(List<Integer> nums) {\n    //\n    //}\n\n    public static List<String> typeTransAllEnToCh(List<String> enTypes) {\n        for (int i = 0; i < enTypes.size(); i++) {\n            for (int j = 0; j < en.length; j++) {\n                if (enTypes.get(i).equals(en[j])) {\n                    enTypes.set(i, ch[j]);\n                }\n            }\n        }\n        enTypes.add(0, \"综合\");\n        return enTypes;\n    }\n\n    /**\n     * 不出意外的话, 这个方法应该用不到.\n     *\n     * @param chTypes\n     * @return\n     */\n    public static List<String> typeTransAllChToEn(List<String> chTypes) {\n        for (int i = 0; i < chTypes.size(); i++) {\n            for (int j = 0; j < ch.length; j++) {\n                if (chTypes.get(i).equals(ch[j])) {\n                    chTypes.set(i, en[j]);\n                }\n            }\n        }\n        chTypes.add(0, \"news_global\");\n        return chTypes;\n    }\n    \n    public static String typeTransSingleEnToCh(String enType) {\n        for (int i = 0; i < en.length; i++) {\n            if (enType.equals(en[i])) {\n                return ch[i];\n            }\n        }\n        return null;\n    }\n    \n    public static String typeTransSingleChToEn(String chType) {\n        for (int i = 0; i < ch.length; i++) {\n            if (chType.equals(ch[i])) {\n                return en[i];\n            }\n        }\n        return null;\n    }\n    \n}\n"
  },
  {
    "path": "back/src/main/resources/mapper/ArtFeatureCountMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.ArtFeatureCountDao\">\n\n    <update id=\"updateArtFeature\">\n        update ArtFeatureCount\n        set ${column} = ${column} + 1, afc_art_time=afc_art_time\n        where afc_art_id = #{artId}\n    </update>\n\n    <select id=\"getArtFeatureCountByArtId\" resultType=\"com.smacul.demo.bean.ArtFeatureCount\">\n        select *\n        from ArtFeatureCount\n        where afc_art_id = #{artId}\n    </select>\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/ArtMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.ArtDao\">\n\n    <insert id=\"addArt\" useGeneratedKeys=\"true\" keyProperty=\"artId\" parameterType=\"com.smacul.demo.bean.Article\">\n        insert into Article(art_title, art_cus_id, art_content, art_image_url, art_type, art_legal)\n        values(#{artTitle}, #{artCusId}, #{artContent}, #{artImageUrl}, #{artType}, #{artLegal})\n    </insert>\n\n    <select id=\"getArtTypesOrderByTypeNum\" resultType=\"java.lang.String\">\n        select art_type from Article group by art_type order by count(art_type) desc\n    </select>\n\n    <select id=\"getTinyArtOnePageFromGlobalNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2)\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyArtOnePageByTypeNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where art_type = #{artType} and\n        art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n        art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getHotArtOnePage\" resultMap=\"artFullModRM\">\n        select\n            art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join ArtTimeList on Article.art_id = ArtTimeList.atl_art_id\n        order by ArtTimeList.atl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getArtFull\" resultMap=\"artFullModRM\">\n        select *\n        from Article\n        where art_id = #{artId}\n    </select>\n\n    <select id=\"getArtCusIdByArtId\" resultType=\"java.lang.Integer\">\n        select art_cus_id from Article where art_id = #{artId}\n    </select>\n\n    <select id=\"getArtTypeByArtId\" resultType=\"java.lang.String\">\n        select art_type from Article where art_id = #{artId}\n    </select>\n\n    <select id=\"searchContentSimple\" resultMap=\"artFullModRM\">\n        select\n            art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where art_title like concat('%', #{key}, '%') or art_content like concat('%', #{key}, '%')\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getSingleArt\" resultType=\"com.smacul.demo.model.ArtFullMod\">\n        select *\n        from Article\n        where 11 != #{flag} and art_id = #{artId}\n    </select>\n\n    <select id=\"getTinyArtOnePageFromGlobalOld\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where\n            art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2)\n            and art_id in (select cbr_art_id from CusBehaviorRecord where cbr_behavior = 2 and cbr_cus_id_from in (${cusIdListStr}))\n            and art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyArtOnePageByTypeOld\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where\n            art_type = #{artType}\n            and art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2)\n            and art_id in (select cbr_art_id from CusBehaviorRecord where cbr_behavior = 2 and cbr_cus_id_from in (${cusIdListStr}))\n            and art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyNewArtFromGlobalForNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article\n        where\n            art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n            art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by art_time desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyHotArtFromGlobalForNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where\n            art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n            art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId}) and\n            art_type not in ('news_travel', 'news_regimen', 'news_story', 'news_history', 'news_baby' 'news_essay', 'news_food', 'news_discovery')\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyInfoArtFromGlobalForNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article left join artscorelist on Article.art_id = artscorelist.asl_art_id\n        where\n            art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n            art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId}) and\n            art_type in ('news_travel', 'news_regimen', 'news_story', 'news_history', 'news_baby' 'news_essay', 'news_food', 'news_discovery')\n        order by artscorelist.asl_art_score desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyNewArtByTypeForNew\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article\n        where art_type = #{artType} and\n        art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n        art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by art_time desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyNewArtFromGlobalForOld\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article\n        where\n            art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2)\n        order by art_time desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getTinyNewArtByTypeForOld\" resultMap=\"artFullModRM\">\n        select art_id, art_title, art_spider, art_type, art_tags, art_image_url, art_time, art_legal, art_cus_id\n        from Article\n        where art_type = #{artType} and\n        art_id not in (select cbr_art_id from CusBehaviorRecord where cbr_cus_id_from = #{cusId} and cbr_behavior = 2) and\n        art_id not in (select crr_art_id from CusRecommendRecord where crr_cus_id = #{cusId})\n        order by art_time desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <resultMap id=\"artFullModRM\" type=\"com.smacul.demo.model.ArtFullMod\">\n        <id property=\"artId\" column=\"art_id\"></id>\n        <result property=\"artTitle\" column=\"art_title\"></result>\n        <result property=\"artTime\" column=\"art_time\"></result>\n        <result property=\"artImageUrl\" column=\"art_image_url\"></result>\n        <result property=\"artCusId\" column=\"art_cus_id\"></result>\n        <result property=\"artContent\" column=\"art_content\"></result>\n        <result property=\"artSpider\" column=\"art_spider\"></result>\n        <result property=\"artLegal\" column=\"art_legal\"></result>\n        <result property=\"artTags\" column=\"art_tags\"></result>\n        <result property=\"artType\" column=\"art_type\"></result>\n        <collection property=\"customer\" select=\"com.smacul.demo.dao.CusDao.getCusById\"\n                    column=\"cusId=art_cus_id\" javaType=\"com.smacul.demo.bean.Customer\"></collection>\n        <collection property=\"artFeature\" select=\"com.smacul.demo.dao.ArtFeatureCountDao.getArtFeatureCountByArtId\"\n                    column=\"artId=art_id\" javaType=\"com.smacul.demo.bean.ArtFeatureCount\"></collection>\n    </resultMap>\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/ArtScoreListMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.ArtScoreListDao\">\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/ArtTimeListMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.ArtTimeList\">\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/ComMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.ComDao\">\n    <insert id=\"addCom\" useGeneratedKeys=\"true\" keyProperty=\"comId\" parameterType=\"com.smacul.demo.bean.Comment\">\n        insert into Comment(com_content, com_legal, com_cus_id, com_art_id)\n        values(#{comContent}, #{comLegal}, #{comCusId}, #{comArtId})\n    </insert>\n\n    <select id=\"getComFullList\" resultMap=\"searchCommentsRM\">\n        select *\n        from Comment\n        where com_art_id = #{artId}\n        order by com_time desc\n    </select>\n\n    <select id=\"getSingleCom\" resultType=\"com.smacul.demo.model.ComFullMod\">\n        select *\n        from Comment\n        where 2 = #{flag} and com_id = #{comId}\n    </select>\n\n    <resultMap id=\"searchCommentsRM\" type=\"com.smacul.demo.model.ComFullMod\">\n        <id property=\"comId\" column=\"com_id\"></id>\n        <result property=\"comArtId\" column=\"com_art_id\"></result>\n        <result property=\"comContent\" column=\"com_content\"></result>\n        <result property=\"comCusId\" column=\"com_cus_id\"></result>\n        <result property=\"comLegal\" column=\"com_legal\"></result>\n        <result property=\"comSpider\" column=\"com_spider\"></result>\n        <result property=\"comTime\" column=\"com_time\"></result>\n        <collection property=\"customer\" select=\"com.smacul.demo.dao.CusDao.getCusById\"\n                    column=\"cusId=com_cus_id\" javaType=\"com.smacul.demo.bean.Customer\"></collection>\n        <collection property=\"replys\" select=\"com.smacul.demo.dao.RepDao.getRepFullList\"\n                    column=\"comId=com_id\" javaType=\"java.util.ArrayList\"></collection>\n    </resultMap>\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/CusBehaviorRecordMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.CusBehaviorRecordDao\">\n\n    <insert id=\"addTargetCusFollowBehavior\">\n        insert into CusBehaviorRecord(cbr_cus_id_from, cbr_cus_id_to, cbr_behavior)\n        values (#{param1}, #{param2}, 11)\n    </insert>\n\n    <insert id=\"addCusBehavior\">\n        insert into CusBehaviorRecord(cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_art_id, cbr_type, cbr_target_id)\n        values (#{cusIdFrom}, #{cusIdTo}, #{behavior}, #{artId}, #{type}, #{targetId})\n    </insert>\n\n    <delete id=\"deleteTargetCusFollowBehavior\">\n        delete from CusBehaviorRecord\n        where cbr_behavior = 11 and cbr_cus_id_from = #{param1} and cbr_cus_id_to = #{param2};\n    </delete>\n\n    <delete id=\"deleteCusBehavior\">\n        delete from CusBehaviorRecord\n        where\n            cbr_cus_id_from = #{cusIdFrom} and cbr_cus_id_to = #{cusIdTo} and cbr_behavior = #{behavior} and\n            cbr_art_id = #{artId} and cbr_type = #{type} and cbr_target_id = #{targetId}\n    </delete>\n\n\n    <select id=\"countTargetCusFollowBehavior\" resultType=\"java.lang.Integer\">\n        select count(*)\n        from CusBehaviorRecord\n        where cbr_behavior = 11 and cbr_cus_id_from = #{param1} and cbr_cus_id_to = #{param2};\n    </select>\n\n    <select id=\"countCusBehaviorFrom\" resultType=\"java.lang.Integer\">\n        select count(*)\n        from CusBehaviorRecord\n        where cbr_cus_id_from = #{param1} and cbr_behavior = #{param2}\n    </select>\n\n    <select id=\"countCusBehaviorTo\" resultType=\"java.lang.Integer\">\n        select count(*)\n        from CusBehaviorRecord\n        where cbr_cus_id_to = #{param1} and cbr_behavior = #{param2}\n    </select>\n\n    <select id=\"countTargetCusArtBehaviorFrom\" resultType=\"java.lang.Integer\">\n        select count(*)\n        from CusBehaviorRecord\n        where\n            cbr_cus_id_from = #{cusIdFrom} and cbr_art_id = #{artId}\n            and cbr_behavior = #{behavior} and cbr_type = 1 and cbr_target_id = #{artId}\n    </select>\n\n    <select id=\"countTargetCusArtBehaviorTo\" resultType=\"java.lang.Integer\">\n        select count(*)\n        from CusBehaviorRecord\n        where\n            cbr_cus_id_to = #{cusIdTo} and cbr_art_id = #{artId}\n            and cbr_behavior = #{behavior} and cbr_type = 1 and cbr_target_id = #{artId}\n    </select>\n\n    <select id=\"getCusDynamicByCusId\" resultMap=\"cusDynamicRM\">\n        select *\n        from CusBehaviorRecord\n        where cbr_cus_id_from = #{cusId} and cbr_behavior != 2\n        order by cbr_time desc\n        limit #{start}, #{pageSize}\n    </select>\n\n    <select id=\"getFollowCus\" resultType=\"java.lang.Integer\">\n        select cbr_cus_id_to\n        from CusBehaviorRecord\n        where cbr_cus_id_from = #{cusId} and cbr_behavior = 11\n    </select>\n\n    <resultMap id=\"cusDynamicRM\" type=\"com.smacul.demo.model.CusDynamicMod\">\n        <id property=\"cbrId\" column=\"cbr_id\"></id>\n        <result property=\"cbrCusIdFrom\" column=\"cbr_cus_id_from\"></result>\n        <result property=\"cbrCusIdTo\" column=\"cbr_cus_id_to\"></result>\n        <result property=\"cbrBehavior\" column=\"cbr_behavior\"></result>\n        <result property=\"cbrTime\" column=\"cbr_time\"></result>\n        <result property=\"cbrType\" column=\"cbr_type\"></result>\n        <result property=\"cbrArtId\" column=\"cbr_art_id\"></result>\n        <collection property=\"cusFrom\" select=\"com.smacul.demo.dao.CusDao.getCusById\"\n                    column=\"cusId=cbr_cus_id_from\"\n                    javaType=\"com.smacul.demo.bean.Customer\"></collection>\n        <collection property=\"cusTo\" select=\"com.smacul.demo.dao.CusDao.getCusById\"\n                    column=\"cusId=cbr_cus_id_to\"\n                    javaType=\"com.smacul.demo.bean.Customer\"></collection>\n        <collection property=\"article\" select=\"com.smacul.demo.dao.ArtDao.getSingleArt\"\n                    column=\"{flag=cbr_type, artId=cbr_art_id}\"\n                    javaType=\"com.smacul.demo.model.ArtFullMod\"></collection>\n        <collection property=\"comment\" select=\"com.smacul.demo.dao.ComDao.getSingleCom\"\n                    column=\"{flag=cbr_type, comId=cbr_target_id}\" javaType=\"com.smacul.demo.model.ComFullMod\"></collection>\n        <collection property=\"reply\" select=\"com.smacul.demo.dao.RepDao.getSingleRep\"\n                    column=\"{flag=cbr_type, repId=cbr_target_id}\" javaType=\"com.smacul.demo.model.RepFullMod\"></collection>\n    </resultMap>\n\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/CusFeatureCountMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.CusFeatureCountDao\">\n\n    <insert id=\"initialCusFeature\">\n        insert into CusFeatureCount (cfc_cus_id) value(#{cusId})\n    </insert>\n\n    <update id=\"updateCusFeature\">\n        update CusFeatureCount\n        set ${column} = ${column} + #{num}\n        where cfc_cus_id = #{cusId}\n    </update>\n\n    <select id=\"countBehaviorNum\" resultType=\"java.lang.Integer\">\n        select\n            cfc_news_society + cfc_news_entertainment + cfc_news_tech + cfc_news_military + cfc_news_sports + cfc_news_finance +\n            cfc_news_world + cfc_news_fashion + cfc_news_travel + cfc_news_discovery + cfc_news_baby + cfc_news_regimen +\n            cfc_news_story + cfc_news_essay + cfc_news_game + cfc_news_history + cfc_news_food + cfc_news_car\n        from CusFeatureCount\n        where cfc_cus_id = #{cusId}\n    </select>\n\n    <select id=\"getCusFeatureCountByCusId\" resultType=\"com.smacul.demo.bean.CusFeatureCount\">\n        select *\n        from CusFeatureCount\n        where cfc_cus_id = #{cusId}\n    </select>\n\n    <select id=\"getCusArtTypesBehaviorNums\" resultType=\"java.lang.Integer\">\n        select\n--             cfc_news_society + cfc_news_entertainment + cfc_news_tech + cfc_news_military + cfc_news_sports + cfc_news_finance +\n--             cfc_news_world + cfc_news_fashion + cfc_news_travel + cfc_news_discovery + cfc_news_baby + cfc_news_regimen +\n--             cfc_news_story + cfc_news_essay + cfc_news_game + cfc_news_history + cfc_news_food + cfc_news_car as cfc_news_global,\n            cfc_news_society, cfc_news_entertainment, cfc_news_tech, cfc_news_military, cfc_news_sports, cfc_news_car,\n            cfc_news_finance, cfc_news_world, cfc_news_fashion, cfc_news_travel, cfc_news_discovery, cfc_news_baby,\n            cfc_news_regimen, cfc_news_story, cfc_news_essay, cfc_news_game, cfc_news_history, cfc_news_food,\n        from CusFeatureCount\n        where cfc_cus_id = #{cusId}\n    </select>\n\n    <select id=\"getRelativeCusList\" resultType=\"java.lang.Integer\">\n        select\n            a.cfc_cus_id\n        from CusFeatureCount as a,\n             (select\n                  cfc_news_society, cfc_news_entertainment, cfc_news_tech, cfc_news_military, cfc_news_sports, cfc_news_finance,\n                  cfc_news_world, cfc_news_fashion, cfc_news_travel, cfc_news_discovery, cfc_news_baby, cfc_news_regimen,\n                  cfc_news_story, cfc_news_essay, cfc_news_game, cfc_news_history, cfc_news_food, cfc_news_car\n              from CusFeatureCount where cfc_cus_id = #{cusId}) as b\n        where a.cfc_cus_id != #{cusId}\n        order by\n            SQRT(\n                        POW((cast(a.cfc_news_society as signed) - cast(b.cfc_news_society as signed)), 2) +\n                        POW((cast(a.cfc_news_entertainment as signed) - cast(b.cfc_news_entertainment as signed)), 2) +\n                        POW((cast(a.cfc_news_tech as signed) - cast(b.cfc_news_tech as signed)), 2) +\n                        POW((cast(a.cfc_news_military as signed) - cast(b.cfc_news_military as signed)), 2) +\n                        POW((cast(a.cfc_news_sports as signed) - cast(b.cfc_news_sports as signed)), 2) +\n                        POW((cast(a.cfc_news_finance as signed) - cast(b.cfc_news_finance as signed)), 2) +\n\n                        POW((cast(a.cfc_news_world as signed) - cast(b.cfc_news_world as signed)), 2) +\n                        POW((cast(a.cfc_news_fashion as signed) - cast(b.cfc_news_fashion as signed)), 2) +\n                        POW((cast(a.cfc_news_travel as signed) - cast(b.cfc_news_travel as signed)), 2) +\n                        POW((cast(a.cfc_news_discovery as signed) - cast(b.cfc_news_discovery as signed)), 2) +\n                        POW((cast(a.cfc_news_baby as signed) - cast(b.cfc_news_baby as signed)), 2) +\n                        POW((cast(a.cfc_news_regimen as signed) - cast(b.cfc_news_regimen as signed)), 2) +\n\n                        POW((cast(a.cfc_news_story as signed) - cast(b.cfc_news_story as signed)), 2) +\n                        POW((cast(a.cfc_news_essay as signed) - cast(b.cfc_news_essay as signed)), 2) +\n                        POW((cast(a.cfc_news_game as signed) - cast(b.cfc_news_game as signed)), 2) +\n                        POW((cast(a.cfc_news_history as signed) - cast(b.cfc_news_history as signed)), 2) +\n                        POW((cast(a.cfc_news_food as signed) - cast(b.cfc_news_food as signed)), 2) +\n                        POW((cast(a.cfc_news_car as signed) - cast(b.cfc_news_car as signed)), 2)\n                )\n        limit #{num};\n    </select>\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/CusMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.CusDao\">\n\n    <insert id=\"insertCusForRegister\">\n        insert into Customer(cus_name, cus_pass) values(#{cusName}, #{cusPass});\n    </insert>\n\n    <insert id=\"updateCusBasicInfo\" parameterType=\"com.smacul.demo.bean.Customer\">\n        update Customer\n        set cus_name = #{cusName}, cus_avatar_url = #{cusAvatarUrl}, cus_style = #{cusStyle}, cus_gender = #{cusGender}\n        where cus_id = #{cusId}\n    </insert>\n\n    <update id=\"updateCusBasicInfoWithPass\">\n        update Customer\n        set cus_name = #{cusName}, cus_avatar_url = #{cusAvatarUrl}, cus_style = #{cusStyle}, cus_gender = #{cusGender},\n            cus_pass = #{cusPass}\n        where cus_id = #{cusId}\n    </update>\n\n    <select id=\"getCusByName\" resultType=\"com.smacul.demo.bean.Customer\">\n        select cus_id, cus_name, cus_spider, cus_avatar_url, cus_style, cus_gender, cus_time, cus_legal, cus_pass\n        from Customer where cus_name = #{cusName};\n    </select>\n\n    <select id=\"countCusByName\" resultType=\"java.lang.Integer\">\n        select count(*) from Customer where cus_name = #{cusName};\n    </select>\n\n    <select id=\"getCusById\" resultType=\"com.smacul.demo.bean.Customer\">\n        select\n            cus_id, cus_name, cus_spider, cus_avatar_url, cus_style, cus_gender, cus_time, cus_legal\n        from Customer where cus_id = #{cusId};\n    </select>\n\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/CusRecommendRecordDao.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.CusRecommendRecordDao\">\n\n\n    <insert id=\"addRecommendList\">\n        INSERT INTO CusRecommendRecord(crr_cus_id, crr_art_id)\n        VALUES\n        <foreach collection=\"list\" item=\"tar\" separator=\",\">\n            (#{cusId}, #{tar})\n        </foreach>\n    </insert>\n\n    <delete id=\"deleteOldCommentList\">\n        delete from CusRecommendRecord WHERE crr_cus_id = #{cusId} and timestampdiff(HOUR, crr_time, now()) >= 72\n    </delete>\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/mapper/RepMap.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper\n        PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n        \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n\n<mapper namespace=\"com.smacul.demo.dao.RepDao\">\n\n    <insert id=\"addRep\" useGeneratedKeys=\"true\" keyProperty=\"repId\" parameterType=\"com.smacul.demo.bean.Reply\">\n        insert into Reply(rep_content, rep_type, rep_legal, rep_cus_id, rep_art_id, rep_com_id, rep_rep_id)\n        values (#{repContent}, #{repType}, #{repLegal}, #{repCusId}, #{repArtId}, #{repComId}, #{repRepId})\n    </insert>\n\n    <select id=\"getRepFullList\" resultType=\"com.smacul.demo.model.RepFullMod\">\n        select R.*,\n            C.cus_avatar_url as 'customer.cusAvatarUrl',\n            C.cus_id as 'customer.cusId',\n            C.cus_name as 'customer.cusName'\n        from Reply as R, Customer as C\n        where R.rep_com_id = #{comId} and R.rep_cus_id = C.cus_id\n        order by rep_time desc\n    </select>\n\n    <select id=\"getSingleRep\" resultType=\"com.smacul.demo.model.RepFullMod\">\n        select *\n        from Reply\n        where 3 = #{flag} and rep_id = #{repId}\n    </select>\n\n</mapper>"
  },
  {
    "path": "back/src/main/resources/templates/application.properties.template",
    "content": "spring.datasource.driverClassName = com.mysql.jdbc.Driver\nspring.datasource.url = jdbc:mysql://\nspring.datasource.username =\nspring.datasource.password =\nmybatis.configuration.map-underscore-to-camel-case=true\nmybatis.mapper-locations=classpath:mapper/*.xml"
  },
  {
    "path": "back/src/test/java/com/smacul/demo/DemoApplicationTests.java",
    "content": "package com.smacul.demo;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.context.SpringBootTest;\n\n@SpringBootTest\nclass DemoApplicationTests {\n\n    @Test\n    void contextLoads() {\n    }\n\n}\n"
  },
  {
    "path": "front/.gitignore",
    "content": ".DS_Store\nnode_modules\n/dist\n\n# local env files\n.env.local\n.env.*.local\n\n# Log files\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Editor directories and files\n.idea\n.vscode\n*.suo\n*.ntvs*\n*.njsproj\n*.sln\n*.sw?\n"
  },
  {
    "path": "front/README.md",
    "content": "# front\n\n## Project setup\n```\nyarn install\n```\n\n### Compiles and hot-reloads for development\n```\nyarn serve\n```\n\n### Compiles and minifies for production\n```\nyarn build\n```\n\n### Lints and fixes files\n```\nyarn lint\n```\n\n### Customize configuration\nSee [Configuration Reference](https://cli.vuejs.org/config/).\n"
  },
  {
    "path": "front/babel.config.js",
    "content": "module.exports = {\n  presets: [\n    '@vue/cli-plugin-babel/preset'\n  ]\n}\n"
  },
  {
    "path": "front/package.json",
    "content": "{\n  \"name\": \"front\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"serve\": \"vue-cli-service serve\",\n    \"build\": \"vue-cli-service build\",\n    \"lint\": \"vue-cli-service lint\"\n  },\n  \"dependencies\": {\n    \"core-js\": \"^3.4.4\",\n    \"element-ui\": \"^2.3.6\",\n    \"vue\": \"^2.6.10\",\n    \"vue-blu\": \"^0.1.9\",\n    \"vue-router\": \"^3.1.3\",\n    \"wangeditor\": \"^3.1.1\"\n  },\n  \"devDependencies\": {\n    \"@vue/cli-plugin-babel\": \"^4.1.0\",\n    \"@vue/cli-plugin-eslint\": \"^4.1.0\",\n    \"@vue/cli-plugin-router\": \"^4.1.2\",\n    \"@vue/cli-service\": \"^4.1.0\",\n    \"axios\": \"^0.18.0\",\n    \"babel-eslint\": \"^10.0.3\",\n    \"eslint\": \"^5.16.0\",\n    \"eslint-plugin-vue\": \"^5.0.0\",\n    \"node-sass\": \"^4.13.1\",\n    \"sass-loader\": \"^8.0.2\",\n    \"vue-cli-plugin-axios\": \"^0.0.4\",\n    \"vue-cli-plugin-element-ui\": \"^1.1.4\",\n    \"vue-template-compiler\": \"^2.6.10\"\n  },\n  \"eslintConfig\": {\n    \"root\": true,\n    \"env\": {\n      \"node\": true\n    },\n    \"extends\": [\n      \"plugin:vue/essential\",\n      \"eslint:recommended\"\n    ],\n    \"rules\": {},\n    \"parserOptions\": {\n      \"parser\": \"babel-eslint\"\n    }\n  },\n  \"browserslist\": [\n    \"> 1%\",\n    \"last 2 versions\"\n  ]\n}\n"
  },
  {
    "path": "front/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n    <link rel=\"icon\" href=\"<%= BASE_URL %>favicon.ico\">\n    <title>front</title>\n  </head>\n  <body>\n    <noscript>\n      <strong>We're sorry but front doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>\n    </noscript>\n    <div id=\"app\"></div>\n    <!-- built files will be auto injected -->\n  </body>\n</html>\n"
  },
  {
    "path": "front/src/App.vue",
    "content": "<template>\n    <div id=\"app\">\n        <!--<div id=\"nav\">-->\n        <!--  <router-link to=\"/\">Home</router-link> |-->\n        <!--  <router-link to=\"/about\">About</router-link>-->\n        <!--</div>-->\n        <router-view/>\n    </div>\n</template>\n\n<style>\n    #app {\n        font-family: 'Avenir', Helvetica, Arial, sans-serif;\n        -webkit-font-smoothing: antialiased;\n        -moz-osx-font-smoothing: grayscale;\n        text-align: center;\n        color: #2c3e50;\n    }\n\n    #nav {\n        padding: 30px;\n    }\n\n    #nav a {\n        font-weight: bold;\n        color: #2c3e50;\n    }\n\n    #nav a.router-link-exact-active {\n        color: #42b983;\n    }\n\n    .clear-float:after {\n        content: '.';\n        display: block;\n        height: 0;\n        clear: both;\n        visibility: hidden;\n    }\n\n    .clear-float {\n        zoom: 1;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/assets/css/Narrow.css",
    "content": "body {\n    margin: 0 auto;\n}\n\nheader {\n    height: 60px;\n    margin-bottom: 10px;\n    box-shadow: 0 1px 4px 0 rgba(0,0,0,.12);\n\n    width: 1000000px;\n    overflow: hidden;\n    position: fixed;\n    background-color: #fff;\n    z-index: 10;\n    top: 0;\n}\n\nmain {\n    width: 1030px;\n    margin: 70px auto 10px;\n    position: relative;\n    z-index: 1;\n    height: 1000px;\n}\n\n/*nav {*/\n/*    width: 130px;*/\n/*    position: fixed;*/\n/*}*/\n\narticle {\n    margin-left:0;\n    width: 710px;\n}\n\naside {\n    width: 280px;\n    position: fixed;\n    top: 70px;\n    margin-left: 750px;\n}\n\n.top-bar {\n    width: 1030px;\n    height: 40px;\n    padding: 10px 0px 10px 0px;\n    position: fixed;\n    left: -515px;\n    margin-left: 50%;\n}"
  },
  {
    "path": "front/src/assets/css/Normal.css",
    "content": "body {\n    margin: 0 auto;\n}\n\nheader {\n    height: 60px;\n    margin-bottom: 10px;\n    box-shadow: 0 1px 4px 0 rgba(0,0,0,.12);\n\n    width: 1000000px;\n    overflow: hidden;\n    position: fixed;\n    background-color: #fff;\n    z-index: 10;\n    top: 0;\n}\n\nmain {\n    width: 1180px;\n    margin: 70px auto 10px;\n    position: relative;\n    z-index: 1;\n    height: 1000px;\n}\n\nnav {\n    width: 130px;\n    position: fixed;\n    z-index: 2;\n}\n\narticle {\n    margin-left:160px;\n    width: 710px;\n    z-index: 1;\n}\n\naside {\n    width: 280px;\n    position: fixed;\n    top: 70px;\n    margin-left: 900px;\n}\n\n.top-bar {\n    width: 1180px;\n    height: 40px;\n    padding: 10px 0px 10px 0px;\n    position: fixed;\n    left: -590px;\n    margin-left: 50%;\n}\n\n"
  },
  {
    "path": "front/src/components/HelloWorld.vue",
    "content": "<template>\n  <div class=\"hello\">\n    <h1>{{ msg }}</h1>\n    <p>\n      For a guide and recipes on how to configure / customize this project,<br>\n      check out the\n      <a href=\"https://cli.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-cli documentation</a>.\n    </p>\n    <h3>Installed CLI Plugins</h3>\n    <ul>\n      <li><a href=\"https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel\" target=\"_blank\" rel=\"noopener\">babel</a></li>\n      <li><a href=\"https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint\" target=\"_blank\" rel=\"noopener\">eslint</a></li>\n    </ul>\n    <h3>Essential Links</h3>\n    <ul>\n      <li><a href=\"https://vuejs.org\" target=\"_blank\" rel=\"noopener\">Core Docs</a></li>\n      <li><a href=\"https://forum.vuejs.org\" target=\"_blank\" rel=\"noopener\">Forum</a></li>\n      <li><a href=\"https://chat.vuejs.org\" target=\"_blank\" rel=\"noopener\">Community Chat</a></li>\n      <li><a href=\"https://twitter.com/vuejs\" target=\"_blank\" rel=\"noopener\">Twitter</a></li>\n      <li><a href=\"https://news.vuejs.org\" target=\"_blank\" rel=\"noopener\">News</a></li>\n    </ul>\n    <h3>Ecosystem</h3>\n    <ul>\n      <li><a href=\"https://router.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-router</a></li>\n      <li><a href=\"https://vuex.vuejs.org\" target=\"_blank\" rel=\"noopener\">vuex</a></li>\n      <li><a href=\"https://github.com/vuejs/vue-devtools#vue-devtools\" target=\"_blank\" rel=\"noopener\">vue-devtools</a></li>\n      <li><a href=\"https://vue-loader.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-loader</a></li>\n      <li><a href=\"https://github.com/vuejs/awesome-vue\" target=\"_blank\" rel=\"noopener\">awesome-vue</a></li>\n    </ul>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'HelloWorld',\n  props: {\n    msg: String\n  }\n}\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\nh3 {\n  margin: 40px 0 0;\n}\nul {\n  list-style-type: none;\n  padding: 0;\n}\nli {\n  display: inline-block;\n  margin: 0 10px;\n}\na {\n  color: #42b983;\n}\n</style>\n"
  },
  {
    "path": "front/src/components/app/HelloWorld.vue",
    "content": "<template>\n  <div class=\"hello\">\n    <h1>{{ msg }}</h1>\n    <p>\n      For a guide and recipes on how to configure / customize this project,<br>\n      check out the\n      <a href=\"https://cli.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-cli documentation</a>.\n    </p>\n    <h3>Installed CLI Plugins</h3>\n    <ul>\n      <li><a href=\"https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel\" target=\"_blank\" rel=\"noopener\">babel</a></li>\n      <li><a href=\"https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint\" target=\"_blank\" rel=\"noopener\">eslint</a></li>\n    </ul>\n    <h3>Essential Links</h3>\n    <ul>\n      <li><a href=\"https://vuejs.org\" target=\"_blank\" rel=\"noopener\">Core Docs</a></li>\n      <li><a href=\"https://forum.vuejs.org\" target=\"_blank\" rel=\"noopener\">Forum</a></li>\n      <li><a href=\"https://chat.vuejs.org\" target=\"_blank\" rel=\"noopener\">Community Chat</a></li>\n      <li><a href=\"https://twitter.com/vuejs\" target=\"_blank\" rel=\"noopener\">Twitter</a></li>\n      <li><a href=\"https://news.vuejs.org\" target=\"_blank\" rel=\"noopener\">News</a></li>\n    </ul>\n    <h3>Ecosystem</h3>\n    <ul>\n      <li><a href=\"https://router.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-router</a></li>\n      <li><a href=\"https://vuex.vuejs.org\" target=\"_blank\" rel=\"noopener\">vuex</a></li>\n      <li><a href=\"https://github.com/vuejs/vue-devtools#vue-devtools\" target=\"_blank\" rel=\"noopener\">vue-devtools</a></li>\n      <li><a href=\"https://vue-loader.vuejs.org\" target=\"_blank\" rel=\"noopener\">vue-loader</a></li>\n      <li><a href=\"https://github.com/vuejs/awesome-vue\" target=\"_blank\" rel=\"noopener\">awesome-vue</a></li>\n    </ul>\n  </div>\n</template>\n\n<script>\nexport default {\n  name: 'HelloWorld',\n  props: {\n    msg: String\n  }\n}\n</script>\n\n<!-- Add \"scoped\" attribute to limit CSS to this component only -->\n<style scoped>\n  h3 {\n    margin: 40px 0 0;\n  }\n  ul {\n    list-style-type: none;\n    padding: 0;\n  }\n  li {\n    display: inline-block;\n    margin: 0 10px;\n  }\n  a {\n    color: #42b983;\n  }\n</style>\n"
  },
  {
    "path": "front/src/components/article/ArticleCenter.vue",
    "content": "<template>\n    <div class=\"article-main\">\n        <div class=\"title\">{{articleMain.artTitle}}</div>\n        <div class=\"article-info\">\n            <span class=\"type\"> {{ articleMain.artType }}</span>\n            <span style=\"margin-right: 5px;\">{{ articleMain.cusName }}</span>\n            <span>{{ dataTransfer }}</span>\n        </div>\n        <div class=\"content\" v-html=\"articleMain.artContent\"></div>\n        <!--<div class=\"up-down clear-float\">-->\n        <!--    <div class=\"up\">-->\n        <!--        <img :src='control.art.up' @click=\"cusLikeArt\"/>-->\n        <!--        <span>{{ articleMain.artLikeNum }}</span>-->\n        <!--    </div>-->\n        <!--    <div class=\"down\">-->\n        <!--        <img :src=\"control.art.down\" @click=\"cusDislikeArt\"/>-->\n        <!--        <span>{{ articleMain.artDislikeNum }}</span>-->\n        <!--    </div>-->\n        <!--</div>-->\n    </div>\n</template>\n\n<script>\n    export default {\n        name: \"ArticleCenter\",\n        props: ['articleMain'],\n        computed: {\n            dataTransfer: function () {\n                return new Date(Date.parse(this.articleMain.artTime)).toLocaleString();\n            }\n        },\n        methods: {\n            cusLikeArt: function () {\n                if (this.control.art.up === require('../../assets/icon/Like.png')) {\n                    this.control.art.up = require('../../assets/icon/LikeFill.png');\n                    this.control.art.down = require('../../assets/icon/Dislike.png');\n                } else {\n                    this.control.art.up = require('../../assets/icon/Like.png');\n                }\n            },\n            cusDislikeArt: function () {\n                if (this.control.art.down === require('../../assets/icon/Dislike.png')) {\n                    this.control.art.down = require('../../assets/icon/DislikeFill.png');\n                    this.control.art.up = require('../../assets/icon/Like.png');\n                } else {\n                    this.control.art.down = require('../../assets/icon/Dislike.png')\n                }\n            }\n        },\n        data: function() {\n            return {\n                control: {\n                    art: {\n                        up: require('../../assets/icon/Like.png'),\n                        down: require('../../assets/icon/Dislike.png'),\n                    }\n                },\n                // likeImg: require('../../assets/icon/Like.png'),\n                // dislikeImg: require('../../assets/icon/Dislike.png'),\n                // likeImgFill: require('../../assets/icon/LikeFill.png'),\n                // dislikeImgFill: require('../../assets/icon/DislikeFill.png'),\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .title {\n        font-size: 40px;\n        font-weight: 800;\n        text-align: left;\n        line-height: 70px;\n    }\n\n    .article-info {\n        text-align: left;\n        margin-top: 10px;\n        margin-bottom: 20px;\n        color: #777777;\n    }\n\n    .content >>> p {\n        text-align: left;\n        font-size: 18px;\n        margin: 10px;\n    }\n\n    .content >>> img {\n        text-align: center;\n    }\n\n    .content {\n        margin-bottom: 30px;\n    }\n\n    .up-down {\n        width: 200px;\n        margin: 0 auto;\n        padding: 30px 0px\n    }\n\n    .up {\n        float: left;\n        height: 30px;\n        width: 50px;\n    }\n\n    .up img {\n        height: 30px;\n        float: left;\n    }\n\n    .up span {\n        display: inline-block;\n        line-height: 30px;\n        font-size: 20px;\n        float: right;\n    }\n\n    /*.el-icon-success {*/\n    /*    margin-right: 10px;*/\n    /*}*/\n\n    .down {\n        float: right;\n        height: 30px;\n        width: 50px;\n    }\n\n    .down img {\n        height: 30px;\n        float: left;\n    }\n\n    .down span {\n        display: inline-block;\n        line-height: 30px;\n        font-size: 20px;\n        float: right;\n    }\n\n    /*.el-icon-error {*/\n    /*    margin-right: 10px;*/\n    /*}*/\n\n    .article-info .type {\n        margin-right: 10px;\n        border: 1px;\n        border-style: solid;\n        border-radius: 3px;\n        color: darkred;\n    }\n</style>"
  },
  {
    "path": "front/src/components/article/CommentReplyCenter.vue",
    "content": "<template>\n    <div>\n        <comment-reply-input :customer=\"customer\" @messageHandler=\"addComment\"></comment-reply-input>\n        <div class=\"comments\" v-for=\"(comment, i) in comments.slice((control.com.page-1)*control.com.pageSize, (control.com.page)*control.com.pageSize)\" :key=\"i\">\n            <div class=\"clear-float\">\n                <div class=\"avatar\">\n                    <img :src='comment.customer.cusAvatarUrl'>\n                </div>\n                <div class=\"comment\">\n                    <div style=\"text-align: left; font-weight: 500; font-size: 18px;\">\n                        <el-button type=\"text\" @click=\"jumpToCus(comment.customer.cusId)\">{{comment.customer.cusName}}</el-button>\n                    </div>\n                    <!--<div class=\"content\">{{comment.comContent}}</div>-->\n                    <div class=\"content\" v-html=\"comment.comContent\"></div>\n                    <div class=\"info\">\n                        <span>{{ date(comment.comTime) }}</span>\n                        <!--<span>{{comment.comLikeNum}}</span>-->\n                        <el-button type=\"text\" @click=\"addCancelReply(comment.comId)\">\n                            <span v-show=\"control.add.type == 1 && control.add.id == comment.comId\">收起</span>\n                            <span v-show=\"control.add.type != 1 || control.add.id != comment.comId\">评论</span>\n                        </el-button>\n                    </div>\n                </div>\n                <!-- 评论回复输入框 -->\n                <comment-reply-input @readycancel=\"cancelMessage\" @messageHandler=\"addReply\"\n                                     v-if=\"control.add.type == 1 && control.add.id == comment.comId\"\n                                     :heightKey=false :customer=\"customer\">\n                </comment-reply-input>\n            </div>\n\n            <reply-main :replys=comment.replys :commentId=comment.comId :add=\"control.add\" :customer=\"customer\"\n                        @quickShow=\"$emit('quickShow')\">\n            </reply-main>\n        </div>\n        <el-pagination v-if=\"comments.length > control.com.pageSize\"\n                       background\n                       layout=\"prev, pager, next\"\n                       @current-change=\"commentHandleCurrentChange\"\n                       :page-size=\"control.com.pageSize\"\n                       :current-page=\"control.com.page\"\n                       :total=\"comments.length\"\n                       class=\"page-switcher\"\n        >\n        </el-pagination>\n    </div>\n</template>\n\n<script>\n    import CommentReplyInput from \"./comment-reply-main/CommentReplyInput\";\n    import ReplyMain from \"./comment-reply-main/ReplyMain\";\n    import {transUTCtoLocal} from \"../../util/TimeHandler\";\n    import {addNewCom, cusAddReply} from \"../../control/Discuss\";\n    import {jumpInNewPage} from \"../../util/PageJump\";\n\n    /**\n     * /src/components/article/comment-reply-main/ 路径下包含了 CommentReplyMain 模块需要的子组件\n     */\n    export default {\n        name: \"CommentReplyCenter\",\n        components: {ReplyMain, CommentReplyInput},\n        props: [\"comments\", 'customer'],\n        methods: {\n            cancelMessage: function() {\n                this.control.add.id = -1;\n            },\n            addCancelReply(comId) {\n                if (this.control.add.type === 1 && this.control.add.id === comId) {\n                    this.control.add.type = -1;\n                    this.control.add.id = -1;\n                } else {\n                    this.control.add.type = 1;\n                    this.control.add.id = comId;\n                }\n            },\n            commentHandleCurrentChange(val) {\n                this.control.com.page = val;\n                this.control.type = -1;\n                this.control.id = -1;\n                let artHeight = document.getElementsByClassName('article-main')[0].offsetHeight;\n                let otherHeight = 70 + 15;\n                let scrollHeight = artHeight + otherHeight;\n                window.scrollTo(0, scrollHeight);\n            },\n            date: function (time) {\n                return transUTCtoLocal(time);\n            },\n            /**\n             * 发表评论对文章\n             *\n             * @param message\n             */\n            addComment: function (message) {\n                // let comment = new FormData();\n                // comment.append('comContent', message);\n                // comment.append('comCustomerId', this.customer.cusId);\n                // comment.append('comArticleId', this.comments[0].comArticleId);\n\n                let comment = {\n                    comContent: message,\n                    comCusId: this.customer.cusId,\n                    comArtId: this.comments[0].comArtId,\n                };\n                addNewCom(comment)\n                    .then((response) => {\n                        if(response.data) {\n                            this.$message.info(\"评论成功\");\n                            this.$emit('quickShow');\n                            this.control.com.page = 1;\n                        } else {\n                            this.$message.info(\"评论失败\");\n                        }\n                    })\n            },\n\n            /**\n             * 添加回复\n             *\n             * @param message\n             */\n            addReply: function (message) {\n                // let reply = new FormData();\n                // reply.append('repContent', message);\n                // reply.append('repType', 0);\n                // reply.append('repCustomerId', this.customer.cusId);\n                // reply.append('repArticleId', this.comments[0].comArticleId);\n                // reply.append('repCommentId', this.control.add.id);\n                let reply = {\n                    repContent: message,\n                    repType: 0,\n                    repCusId: this.customer.cusId,\n                    repArtId: this.comments[0].comArtId,\n                    // 回复针对的评论的 id\n                    repComId: this.control.add.id,\n                };\n                cusAddReply(reply)\n                    .then((response) => {\n                        if (response.data) {\n                            this.$message.info(\"回复成功\");\n                            this.$emit('quickShow');\n                            // todo 这个地方要重新计算一遍位置\n                        } else {\n                            this.$message.info(\"回复失败\");\n                        }\n                    });\n                this.control.add.type = -1;\n                this.control.add.id = -1;\n            },\n            jumpToCus: function (cusId) {\n                jumpInNewPage('/self/' + cusId);\n            }\n        },\n        data: function() {\n            return {\n                control: {\n                    com: {\n                        page: 1,\n                        pageSize: 8,\n                    },\n                    add: {\n                        type: -1,\n                        id: -1,\n                    }\n                }\n            }\n        },\n\n    }\n</script>\n\n<style scoped>\n    .comments {\n        margin-bottom: 10px;\n    }\n\n    .reply-main {\n        margin-left: 10%;\n        margin-bottom: 5px;\n    }\n\n    .avatar {\n        float: left;\n        margin-right: 3%;\n        width: 7%;\n    }\n\n    .avatar img{\n        width: 100%;\n    }\n\n    .comment {\n        float: left;\n        width: 90%;\n    }\n\n    .name {\n        font-size: 20px;\n        font-weight: 600;\n        text-align: left;\n        margin-bottom: 5px;\n        float: left;\n    }\n\n    .reply {\n        float: left;\n    }\n\n    .content {\n        font-size: 16px;\n        line-height: 20px;\n        text-align: left;\n        word-wrap: break-word;\n    }\n\n    .info {\n        font-size: 14px;\n        color: #888888;\n        text-align: left;\n    }\n\n    .info span {\n        margin-right: 10px;\n    }\n\n    .content >>> p {\n        margin: 0;\n    }\n\n    .page-switcher {\n        float: left;\n        padding-bottom: 50px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/article/RightMenu.vue",
    "content": "<template>\n    <div>\n        <editor-brief class=\"editor-brief\" :articleAuthor=\"articleAuthor\"></editor-brief>\n        <edit-entrance class=\"edit-entrance\"></edit-entrance>\n        <hot-article :title=\"hotArticle.title\" :hot-articles=\"hotArticle.hotArticles\"></hot-article>\n    </div>\n</template>\n\n\n<script>\n    import EditEntrance from '../common/EditEntrance'\n    import HotArticle from '../common/HotArticle'\n\n    import Logo from '../../assets/image/Logo.png'\n    import EditorBrief from \"../common/EditorBrief\";\n\n    export default {\n        name: 'RightMenu',\n        components: {\n            EditorBrief,\n            EditEntrance, HotArticle\n        },\n        data: function () {\n            return {\n                hotArticle: {\n                    title: '相关新闻',\n                    hotArticles: [\n                        { artId: '1', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '2', artTitle: 'This is the template title of news', artImage: ''},\n                        { artId: '3', artTitle: 'This is the template title of news', artImage: ''},\n                        { artId: '4', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '5', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '6', artTitle: 'This is the template title of news', artImage: Logo},\n                    ]\n                },\n                articleAuthor: {\n                    cusId: 6,\n                    cusName: '中国新闻网',\n                    cusAvatarUrl: 'https://p3.pstatp.com/large/97d001bf3f3cba72913',\n                },\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .editor-brief, .edit-entrance {\n        margin-bottom: 10px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/article/TopBar.vue",
    "content": "<template>\n    <div class=\"clear-float\">\n        <div class=\"body-image\" v-on:click=\"jumpToIndex\">\n            <img src=\"@/assets/image/Logo.png\"/>\n        </div>\n        <search-panel :tip=\"tip\"  v-on:search=\"searchArticles\"></search-panel>\n        <div class=\"manage\">\n            <img v-if=\"customer.cusAvatarUrl !== ''\" :src=\"customer.cusAvatarUrl\" v-on:click=\"jumpToSelf\"/>\n            <img v-if=\"customer.cusAvatarUrl === ''\" :src=\"manSrc\" v-on:click=\"jumpToSelf\"/>\n            <el-button type=\"text\" @click=\"loginOut\">退出登录</el-button>\n        </div>\n    </div>\n</template>\n\n<script>\n    import SearchPanel from '../common/SearchPanel'\n    import Man from '../../assets/image/Man.png'\n    import {jumpInCurPage, jumpInNewPage} from \"../../util/PageJump\";\n    import {quitLogin} from \"../../control/Self\";\n\n    export default {\n        name: 'TopBar',\n        props: ['message', 'customer'],\n        components: {SearchPanel},\n        methods: {\n            jumpToIndex: function() {\n                jumpInCurPage('/index/');\n            },\n            jumpToSelf: function() {\n                jumpInNewPage('/self/' + this.customer.cusId)\n            },\n            searchArticles: function (message) {\n                jumpInNewPage('/search/' + message )\n                // searchContentByKeyAndTagTypePage(message, 'global', 'test', 0, 10)\n            },\n            loginOut: function () {\n                quitLogin()\n                    .then((response) => {\n                        if (response.data === '退出成功') {\n                            this.$router.push({path: '/port'});\n                        }\n                    })\n            }\n        },\n        data: function() {\n            return {\n                tip: '搜索',\n                manSrc: Man,\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n\n    .body-image {\n        float: left;\n        height: 40px;\n        margin-top: 5px;\n    }\n\n    .body-image img {\n        height: 30px;\n        width: 130px;\n    }\n\n    .manage {\n        float: right;\n        height: 40px;\n        padding-top: 5px;\n    }\n\n    .manage >>> .el-button {\n        font-size: 16px;\n        height: 40px;\n        float: right;\n    }\n\n    .manage img {\n        width: 30px;\n        height: 30px;\n        /*padding: 5px 10px;*/\n        margin-right: 5px;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/article/comment-reply-main/CommentReplyInput.vue",
    "content": "<template>\n    <div class=\"comment-reply-input\">\n        <div class=\"avatar\">\n            <img :src=\"customer.cusAvatarUrl\" style=\"width: 100%\"/>\n        </div>\n        <div style=\"width: 90%\">\n            <div ref=\"toolbar\" class=\"toolbar\">\n                <div style=\"position: absolute; display: inherit; right: 0px; width: 120px;\">\n                    <el-button class=\"cancel\" type=\"primary\" @click=\"cancel\">取消</el-button>\n                    <el-button type=\"primary\" @click=\"showMessage\"\n                               style=\"padding: 5px; width: 70px\">发表</el-button>\n                </div>\n            </div>\n            <div ref=\"textplace\" class=\"textplace\" :style=\"{height: height}\" @click=\"changeHeight\"></div>\n        </div>\n    </div>\n</template>\n\n<script>\n    import WangEditor from 'wangeditor'\n    // import Man from '../../../assets/image/Man.png'\n    // import Man from '@/assets/image/Man.png'\n\n    export default {\n        name: \"CommentReplyInput\",\n        props: ['heightKey', 'customer'],\n        data: function() {\n            return {\n                height: '70px',\n\n                DEFAULT_HEIGHT: '70px',\n                EDIT_HEIGHT: '210px',\n\n                menus: [\n                    'source', 'bold', 'underline', 'italic', 'emotion', 'undo', 'redo', 'fullscreen', 'emoticon',\n                ],\n                editor: null,\n                message: 'message',\n                // manSrc: Man,\n            }\n        },\n        mounted() {\n            let editor = new WangEditor(this.$refs.toolbar, this.$refs.textplace);\n            this.editor = editor;\n            editor.customConfig.onchange = (html) => {\n                this.message = html;\n            };\n            editor.customConfig.menus = this.menus;\n            editor.create();\n        },\n        methods: {\n            /**\n             * 向上级组件返回用户输入的内容\n             */\n            showMessage() {\n                // alert(this.message);\n                this.$emit('messageHandler', this.message);\n                this.editor.txt.clear();\n            },\n            changeHeight() {\n                if (this.heightKey) {\n                    this.height = this.EDIT_HEIGHT;\n                }\n            },\n            cancel() {\n                if (this.heightKey) {\n                    this.height = this.DEFAULT_HEIGHT;\n                    this.editor.txt.clear();\n                } else {\n                    this.editor.txt.clear();\n                    this.$emit('readycancel');\n                }\n\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .comment-reply-input {\n        display: flex;\n        width: 100%;\n    }\n\n    .avatar {\n        width: 7%;\n        margin-right: 3%;\n    }\n\n    .toolbar {\n        height: 30px;\n        border: 0px solid #f1f1f1;\n        background-color:#f1f1f1;\n        position: relative;\n    }\n\n    .toolbar .el-button {\n        line-height: 20px;\n    }\n\n    .toolbar .el-button--primary {\n        border: none;\n        border-radius: 0px;\n        margin: 0px;\n    }\n\n    /* 取消按钮 */\n    .toolbar .el-button.cancel.el-button--primary {\n        padding: 5px;\n        width: 50px;\n        background-color: #888888;\n    }\n\n    /* 取消按钮 */\n    .toolbar .el-button.cancel.el-button--primary:hover {\n        background-color: #989797;\n    }\n\n    .textplace {\n        /* height: 80px; */\n        border: 1px solid #f1f1f1;\n        text-align: left;\n        margin-bottom: 40px;\n        /*overflow: hidden;*/\n    }\n\n    .textplace >>> .w-e-text {\n        padding: 5px 10px;\n    }\n\n    .textplace >>> .w-e-text p {\n        margin: 0;\n        line-height: 20px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/article/comment-reply-main/ReplyMain.vue",
    "content": "<template>\n    <div class=\"reply-main\">\n        <div  v-for=\"(reply, i) in replys.slice((control.rep.page-1)*control.rep.pageSize, (control.rep.page)*control.rep.pageSize)\" :key=\"i\">\n            <div class=\"clear-float\">\n                <div class=\"avatar\">\n                    <img :src=\"reply.customer.cusAvatarUrl\">\n                </div>\n                <div class=\"comment\">\n                    <div style=\"text-align: left; font-weight: 500; font-size: 18px;\">\n                        <!--<el-button type=\"text\">文字按钮</el-button>-->\n                        <el-button type=\"text\" @click=\"jumpToCus(reply.customer.cusId)\">{{reply.customer.cusName}}</el-button>\n                        <span style=\"font-weight:400; font-size:16px;\" v-if=\"reply.repRepId !== null\"> 回复 </span>\n                        <el-button type=\"text\" v-if=\"reply.repRepId !== null\" @click=\"jumpToCus(findReplyTarget(reply.repRepId).cusId)\">{{ findReplyTarget(reply.repRepId).cusName }}</el-button>\n                    </div>\n                    <!--<div class=\"content\">{{reply.repContent}}</div>-->\n                    <div class=\"content\" v-html=\"reply.repContent\"></div>\n                    <div class=\"info\">\n                        <span>{{ date(reply.repTime) }}</span>\n                        <el-button type=\"text\" @click=\"addCancelReply(reply.repId)\">\n                            <span v-show=\"add.type === 2 && add.id === reply.repId\">收起</span>\n                            <span v-show=\"add.type !== 2 || add.id !== reply.repId\">评论</span>\n                        </el-button>\n                    </div>\n                </div>\n                <!-- 评论回复输入框 -->\n                <comment-reply-input @readycancel=\"cancelMessage\" @messageHandler=\"addReply\"\n                                     v-if=\"add.type === 2 && add.id === reply.repId\"\n                                     :heightKey=false :customer=\"customer\">\n                </comment-reply-input>\n            </div>\n\n        </div>\n        <el-pagination v-if=\"replys.length > control.rep.pageSize\"\n                       small\n                       layout=\"prev, pager, next\"\n                       @current-change=\"replyHandleCurrentChange\"\n                       :page-size=\"control.rep.pageSize\"\n                       :current-page=\"control.rep.page\"\n                       :total=\"replys.length\"\n        >\n        </el-pagination>\n    </div>\n</template>\n\n<script>\n    import CommentReplyInput from \"./CommentReplyInput\";\n    import {transUTCtoLocal} from \"../../../util/TimeHandler\";\n    import {cusAddReply} from \"../../../control/Discuss\";\n    import {jumpInNewPage} from \"../../../util/PageJump\";\n    export default {\n        name: \"ReplyMain\",\n        components: {CommentReplyInput},\n        props: ['replys', 'comId', 'add', 'customer'],\n        methods: {\n            replyHandleCurrentChange(val) {\n                this.control.rep.page = val;\n                this.add.type = -1;\n                this.add.id = -1;\n            },\n            addCancelReply(repId) {\n                if (this.add.type == 2 && this.add.id == repId) {\n                    this.add.type = -1;\n                    this.add.id  = -1;\n                } else {\n                    this.add.type = 2;\n                    this.add.id = repId;\n                }\n            },\n            cancelMessage() {\n                this.add.type = -1;\n                this.add.id  = -1;\n            },\n            findReplyTarget(id) {\n                let result = '';\n                this.replys.forEach((item) => {\n                    if (item.repId === id) {\n                        result = item.customer;\n                    }\n                });\n                return result;\n            },\n            date: function (time) {\n                return transUTCtoLocal(time)\n            },\n            addReply: function (message) {\n                let reply = {\n                    repContent: message,\n                    repType: 1,\n                    repCusId: this.customer.cusId,\n                    repArtId: this.replys[0].repArtId,\n                    // 回复针对的评论的 id\n                    repComId: this.replys[0].repComId,\n                    repRepId: this.add.id,\n                };\n                cusAddReply(reply)\n                    .then((response) => {\n                        if (response.data) {\n                            this.$message.info(\"回复成功\");\n                            this.$emit('quickShow');\n                            this.control.rep.page = 1;\n                        } else {\n                            this.$message.info(\"回复失败\");\n                        }\n                    });\n\n                this.add.type = -1;\n                this.add.id = -1;\n            },\n            jumpToCus: function (cusId) {\n                jumpInNewPage('/self/' + cusId);\n            }\n        },\n        data: function () {\n            return {\n                control: {\n                    rep: {\n                        page: 1,\n                        pageSize: 4,\n                    }\n                }\n            }\n        },\n    }\n</script>\n\n<style scoped>\n    .avatar {\n        float: left;\n        margin-right: 3%;\n        width: 7%;\n    }\n\n    .avatar img{\n        width: 100%;\n    }\n\n    .comment {\n        float: left;\n        width: 90%;\n    }\n\n    .name {\n        font-size: 20px;\n        font-weight: 600;\n        text-align: left;\n        margin-bottom: 5px;\n        float: left;\n    }\n\n    .reply {\n        float: left;\n    }\n\n    .content {\n        font-size: 16px;\n        line-height: 20px;\n        text-align: left;\n        word-wrap: break-word;\n    }\n\n    .info {\n        font-size: 14px;\n        color: #888888;\n        text-align: left;\n    }\n\n    .info span {\n        margin-right: 10px;\n    }\n\n    .content >>> p {\n        margin: 0;\n    }\n</style>"
  },
  {
    "path": "front/src/components/common/DarkCard.vue",
    "content": "<template>\n    <div class=\"dark-card\">\n        <slot></slot>\n    </div>\n</template>\n\n<script>\n    export default {\n        name: \"CardPanel\"\n    }\n</script>\n\n<style scoped>\n    .dark-card {\n        padding: 15px;\n        background-color: #f4f5f6;\n        border: solid 1px #ebeef5;\n    }\n</style>"
  },
  {
    "path": "front/src/components/common/EditEntrance.vue",
    "content": "<template>\n    <card-panel>\n        <img class=\"body-image\" :src=\"logoSrc\"/>\n        <div class=\"body-title\">\n            <!--<span>点击</span>-->\n            <el-button type=\"text\" @click=\"jumpToEdit\">点击</el-button>\n            <span>开始书写自己的新闻</span>\n        </div>\n    </card-panel>\n</template>\n\n<script>\n    import Logo from '../../assets/image/Pen.png'\n    import CardPanel from './DarkCard'\n    import {jumpInNewPage} from \"../../util/PageJump\";\n    export default {\n        name: 'EditEntrance',\n        components: {CardPanel},\n        methods: {\n            jumpToEdit: function () {\n                jumpInNewPage('/edit');\n            }\n        },\n        data: function() {\n            return {\n                logoSrc: Logo\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .body-image {\n        height: 50px;\n    }\n\n    .body-title .el-button >>> span {\n        font-size: 16px;\n        font-weight: 500;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/common/EditorBrief.vue",
    "content": "<template>\n    <dark-card>\n        <div class=\"clear-float\">\n            <img class=\"image\" :src=\"articleAuthor.cusAvatarUrl\"/>\n            <div class=\"editor-follow\">\n                <span class=\"editor\" @click=\"jumpToCustomer(articleAuthor.cusId)\"> {{articleAuthor.cusName}}</span>\n                <el-button class=\"follow\" type=\"primary\" v-if=\"!artSelfStatus.follow\"\n                           :disabled=\"customer.cusId === articleAuthor.cusId\" @click=\"followCustomer\">\n                    +关注</el-button>\n                <el-button class=\"follow\" type=\"success\" v-if=\"artSelfStatus.follow\"\n                           :disabled=\"customer.cusId === articleAuthor.cusId\" @click=\"followCustomer\">\n                    取消关注</el-button>\n            </div>\n        </div>\n    </dark-card>\n</template>\n\n<script>\n    import DarkCard from './DarkCard'\n    import {setCusFollow} from \"../../control/Self\";\n    export default {\n        name: \"EditorBrief\",\n        components: { DarkCard },\n        props: ['articleAuthor', 'customer', 'artSelfStatus'],\n        methods: {\n            jumpToCustomer: function (cusId) {\n                this.$emit('editor', cusId);\n            },\n            followCustomer: function () {\n                setCusFollow(this.articleAuthor.cusId)\n                    .then((response) => {\n                        // alert(response.data);\n                        if (response.data === '关注失败') {\n                            this.artSelfStatus.follow = false;\n                        } else {\n                            this.artSelfStatus.follow = true;\n                        }\n                    })\n            }\n        },\n        data: function () {\n            return {\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .image {\n        height: 50px;\n        float: left;\n        margin: 10px;\n    }\n\n    .editor-follow {\n        height: 50px;\n        float: left;\n        text-align: left;\n        margin: 10px;\n    }\n\n    .editor {\n        display: block;\n        text-align: left;\n        font-size: 16px;\n        line-height: 25px;\n    }\n\n    .editor:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n\n    .el-button {\n        height: 25px;\n        width: 60px;\n        padding: 0px;\n        font-size: 10pt;\n        border-radius: 1px;\n        display: block;\n    }\n</style>"
  },
  {
    "path": "front/src/components/common/FloatCard.vue",
    "content": "<template>\n    <div class=\"float-card\">\n        <slot></slot>\n    </div>\n</template>\n\n<script>\n    export default {\n        name: \"FloatCard\"\n    }\n</script>\n\n<style scoped>\n    .float-card {\n        padding: 15px;\n        border: 0;\n        border-radius: 0;\n        border-bottom: solid 1px rgba(0,0,0,.1);\n        box-shadow: none;\n    }\n\n    .float-card:hover {\n        box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);\n        background-color: #f4f5f6;\n        border-bottom: none;\n    }\n</style>"
  },
  {
    "path": "front/src/components/common/HotArticle.vue",
    "content": "<template>\n    <dark-card>\n        <div class=\"hot-art-header clear-float\">\n            <span class=\"header-title\">{{ title }}</span>\n            <el-button class=\"header-refresh\" type=\"text\" @click=\"refreshArticles\">刷新</el-button>\n        </div>\n        <div class=\"hot-art-body clear-float\" v-for=\"(hotArticle, i) in hotArticles\" :key=\"i\">\n            <img class=\"body-image\" v-if=\"hotArticle.artImageUrl !== ''\" :src=\"hotArticle.artImageUrl\"/>\n            <span class=\"body-title\" :class=\"[hotArticle.artImageUrl !== '' ? narrowTitle : wideTitle]\"\n                  @click=\"jumpToArticle(hotArticle.artId)\">\n                {{ hotArticle.artTitle }}\n            </span>\n        </div>\n    </dark-card>\n</template>\n\n<script>\nimport DarkCard from \"./DarkCard\";\nexport default {\n    components: {DarkCard},\n    props: ['title', 'hotArticles'],\n    name: 'HotArticle',\n    computed: {\n    },\n    methods: {\n        jumpToArticle: function (artId) {\n            this.$emit('jump', artId);\n        },\n        refreshArticles: function () {\n            this.$emit('refresh');\n        },\n    },\n    data: function() {\n        return {\n            narrowTitle: 'narrow-title',\n            wideTitle: 'wide-title'\n\n        }\n    }\n}\n</script>\n\n<style scoped>\n\n    .hot-art-header {\n        border-bottom: solid 1px #ebeef5;\n        margin-bottom: 15px;\n    }\n\n    .header-title {\n        font-size: 20px;\n        font-weight: 800;\n        height:40px;\n        line-height: 40px;\n        float: left;\n    }\n\n    /* 刷新按钮 */\n    .header-refresh {\n        height: 40px;\n        float: right;\n    }\n\n    /* 刷新 两个字 */\n    .header-refresh span {\n        font-size: 16px;\n        font-weight: 500;\n    }\n\n    .hot-art-body {\n        margin-bottom: 10px;\n    }\n\n    .body-image {\n        float: left;\n        height: 50px;\n        width: 27%;\n        margin-right: 3%;\n    }\n\n    /* 新闻标题 */\n    .body-title {\n        float: left;\n        line-height: 25px;\n        font-weight: 500;\n        overflow: hidden;\n        height: 50px;\n        text-align: left;\n    }\n\n    .narrow-title {\n        width: 70%;\n    }\n\n    .wide-title {\n        width: 100%;\n    }\n\n    .body-title:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/common/SearchPanel.vue",
    "content": "<template>\n    <div class=\"search\">\n        <el-input v-model=\"message\" placeholder=\"请输入内容\"></el-input>\n        <el-button type=\"primary\" @click=\"search\">{{tip}}</el-button>\n    </div>\n</template>\n\n<script>\n    /**\n     * 搜索面板\n     *\n     * 调用此模块需要实现 search 监听器, 用于获取输入搜索框中的信息\n     */\n    export default {\n        name: \"SearchPanel\",\n        props: ['tip'],\n        methods: {\n            search: function () {\n                this.$emit('search', this.message);\n            }\n        },\n        data: function () {\n            return {\n                message: '',\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .search {\n        width: 400px;\n        float: left;\n        margin-left: 20%;\n    }\n\n    .search >>> .el-input {\n        width: 300px;\n        float: left;\n    }\n\n    .search >>> .el-input__inner {\n        border-radius: 5px 0px 0px 5px;\n        line-height: unset;\n    }\n\n    .search >>> .el-button {\n        float: left;\n        border-radius: 0px 5px 5px 0px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/common/TinyArticle.vue",
    "content": "<template>\n    <float-card class=\"float-card clear-float\">\n        <div class=\"image\" v-if=\"tinyArticle.artImageUrl !== ''\">\n            <img :src=\"tinyArticle.artImageUrl\" >\n        </div>\n        <div class=\"word\" :class=\"[wideSwitch ? tinyArt : tinyArtWide]\">\n            <div class=\"title\" @click=\"jumpToArticle(tinyArticle.artId)\">{{ tinyArticle.artTitle }}</div>\n            <!--<div>adsfasfdasdf</div>-->\n            <div class=\"info\">\n                <span class=\"type\">{{ tinyArticle.artType}}</span>\n                <span class=\"customer\" @click=\"jumpToCustomer(tinyArticle.customer.cusId)\">{{ tinyArticle.customer.cusName }}</span>\n                <span>{{ date(tinyArticle.artTime) }}</span>\n            </div>\n        </div>\n    </float-card>\n</template>\n\n<script>\n\n    import FloatCard from \"./FloatCard\";\n    import {transUTCtoLocal} from \"../../util/TimeHandler\";\n    export default {\n        name: \"TinyArticle\",\n        props: ['tinyArticle'],\n        components: {FloatCard},\n        computed: {\n            wideSwitch: function () {\n                return this.tinyArticle.artImageUrl !== '';\n            },\n\n        },\n        methods: {\n            jumpToArticle: function (artId) {\n                this.$emit('jump', artId);\n            },\n\n            jumpToCustomer: function (cusId) {\n                this.$emit('editor', cusId);\n            },\n            date: function (time) {\n                return transUTCtoLocal(time);\n            }\n        },\n        data: function() {\n            return {\n                tinyArt: 'tiny-art',\n                tinyArtWide: 'tiny-art-wide',\n            }\n        },\n    }\n</script>\n\n<style scoped>\n\n    .float-card {\n        margin-bottom: 15px;\n    }\n\n    .image img {\n        float: left;\n        width: 27%;\n        height: 120px;\n        margin-right: 3%;\n    }\n\n    .word {\n        float: left;\n        height: 120px;\n        position: relative;\n    }\n\n    .tiny-art {\n        width: 70%;\n    }\n\n    .tiny-art-wide {\n        width: 100%;\n    }\n\n    .title {\n        height: 60px;\n        line-height: 30px;\n        font-size: 18pt;\n        overflow: hidden;\n        text-align: left;\n        margin-bottom: 5px;\n        font-weight: 800;\n    }\n\n    .title:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n\n    .description {\n        height: 20px;\n        line-height: 20px;\n        overflow: hidden;\n        text-align: left;\n        color: #888888;\n    }\n\n    .info {\n        text-align: left;\n        font-size: 14px;\n        position: absolute;\n        bottom: 0;\n        color: #888888;\n    }\n\n    .info .type {\n        margin-right: 10px;\n        border: 1px;\n        border-style: solid;\n        border-radius: 3px;\n        color: darkred;\n    }\n\n    .info :first-child {\n        font-weight: 400;\n    }\n\n    .customer {\n        margin-right: 10px;\n    }\n\n    .customer:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n</style>"
  },
  {
    "path": "front/src/components/edit/TopBar.vue",
    "content": "<template>\n    <div class=\"clear-float\">\n        <div class=\"body-image\" v-on:click=\"jumpToIndex\">\n            <img src=\"@/assets/image/Logo.png\"/>\n        </div>\n        <search-panel :tip=\"tip\"  v-on:search=\"searchArticles\"></search-panel>\n        <div class=\"manage\">\n            <img v-if=\"customer.cusAvatarUrl !== ''\" :src=\"customer.cusAvatarUrl\" v-on:click=\"jumpToSelf\"/>\n            <img v-if=\"customer.cusAvatarUrl === ''\" :src=\"manSrc\" v-on:click=\"jumpToSelf\"/>\n            <el-button type=\"text\" @click=\"loginOut\">退出登录</el-button>\n        </div>\n    </div>\n</template>\n\n<script>\n    import SearchPanel from '../common/SearchPanel'\n    import Man from '../../assets/image/Man.png'\n    import {jumpInCurPage, jumpInNewPage} from \"../../util/PageJump\";\n    import {quitLogin} from \"../../control/Self\";\n\n    export default {\n        name: 'TopBar',\n        props: ['message', 'customer'],\n        components: {SearchPanel},\n        methods: {\n            jumpToIndex: function() {\n                jumpInCurPage('/index/');\n            },\n            jumpToSelf: function() {\n                jumpInNewPage('/self/' + this.customer.cusId)\n            },\n            searchArticles: function (message) {\n                jumpInNewPage('/search/' + message )\n                // searchContentByKeyAndTagTypePage(message, 'global', 'test', 0, 10)\n            },\n            loginOut: function () {\n                quitLogin()\n                    .then((response) => {\n                        if (response.data === '退出成功') {\n                            this.$router.push({path: '/port'});\n                        }\n                    })\n            }\n        },\n        data: function() {\n            return {\n                tip: '搜索',\n                manSrc: Man,\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n\n    .body-image {\n        float: left;\n        height: 40px;\n        margin-top: 5px;\n    }\n\n    .body-image img {\n        height: 30px;\n        width: 130px;\n    }\n\n    .manage {\n        float: right;\n        height: 40px;\n        padding-top: 5px;\n    }\n\n    .manage >>> .el-button {\n        font-size: 16px;\n        height: 40px;\n        float: right;\n    }\n\n    .manage img {\n        width: 30px;\n        height: 30px;\n        /*padding: 5px 10px;*/\n        margin-right: 5px;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/index/LeftMenu.vue",
    "content": "<template>\n    <el-menu :default-active=\"curIndex.toString()\" class=\"el-menu-vertical-demo\">\n        <el-menu-item v-for=\"(artClass, i) in artClassList.slice(0, majorLength)\" :key=\"i\" :index=\"i.toString()\" v-on:click=\"changeCurIndex(i)\">\n            <span slot=\"title\">{{artClass}}</span>\n        </el-menu-item>\n\n        <!-- 二级 种类入口 -->\n        <el-menu-item class=\"more-class\" v-if=\"artClassList.length > majorLength\">\n            <span @mouseenter=\"showPanel(true)\" @mouseleave=\"showPanel(false)\">{{tip}}</span>\n            <div class=\"more-panel\" v-show=\"panel\" @mouseenter=\"showPanel(true)\" @mouseleave=\"showPanel(false)\">\n                <div v-for=\"(lineNum, lineIndex) in Math.ceil((artClassList.length - majorLength) / buttonNum)\" :key=\"lineIndex\">\n                    <el-button type=\"primary\"\n                               v-for=\"(artClass, i) in artClassList.slice(majorLength + lineIndex * buttonNum, majorLength + lineIndex * buttonNum + buttonNum)\"\n                               :key=\"i\" v-on:click=\"changeCurIndex(majorLength + lineIndex * buttonNum + i)\">\n                        {{artClass}}\n                    </el-button>\n                </div>\n            </div>\n        </el-menu-item>\n\n    </el-menu>\n</template>\n\n<script>\n    /**\n     * 类别菜单, 是 LeftMenu 的唯一子组件, 负责内容展示.\n     *\n     * 若调用此模块, 需要实现 changeCurIndex 监听器, 用于获取被选中的种类索引.\n     */\n    export default {\n        props: ['curIndex', 'majorLength', 'tip', 'artClassList'],\n        name: \"LeftMenuInner\",\n        methods: {\n            /**\n             * 修改当前选中的种类, 并通知上级组件\n             * @param index\n             */\n            changeCurIndex: function(index) {\n                this.$emit('changeCurIndex', index);\n                this.showPanel(false)\n            },\n\n            /**\n             * 鼠标划入或划出二级标签入口以及二级标签时, 弹出或收回二级标签面板\n             * @param bool\n             */\n            showPanel: function(bool) {\n                this.panel = bool;\n            }\n        },\n        data: function() {\n            return {\n                // panel 将决定是否显示二级标签版\n                panel: false,\n                // buttonNum: 二级标签面板中, 每一行的按钮数\n                buttonNum: 4,\n            }\n        },\n    }\n</script>\n\n<style scoped>\n    .el-menu {\n        border: none;\n    }\n\n    .el-menu-item {\n        border-radius: 5px;\n        margin-bottom: 5px;\n        font-size: 16px;\n        font-weight: 500;\n        line-height: 40px;\n        height: 40px;\n        padding: 0 !important;\n    }\n\n    .el-menu-item.is-active {\n        border-radius: 5px;\n        color: teal;\n        background-color: #e6f2f2;\n    }\n\n    .el-menu-item:hover {\n        border-radius: 5px;\n        color: teal;\n    }\n\n    .el-menu-item span {\n        display: inline-block;\n        width: 130px;\n    }\n\n    .more-panel {\n        border: solid #E8F2F2 1px;\n        width: 520px;\n        position: absolute;\n        left: 130px;\n        top: -5px;\n        padding: 4px;\n        z-index: 10000;\n        background-color: white;\n    }\n\n    .more-class {\n        position: relative;\n    }\n\n    .more-class .button-span {\n        display: inline-block;\n        width: 130px;\n    }\n\n    .more-class .el-menu-item {\n        border-radius: 5px;\n        margin-bottom: 5px;\n        font-size: 16px;\n        font-weight: 500;\n    }\n\n    /* 更多按钮 */\n    .more-class.el-menu-item:focus {\n        color: teal;\n    }\n\n    .more-class.el-menu-item:hover {\n        border-radius: 5px;\n        color: teal;\n    }\n\n    .more-class.el-menu-item:active {\n        color: teal;\n    }\n\n    /* 二级按钮面板内的按钮 */\n    .more-panel .el-button--primary {\n        background-color: #ffffff;\n        border: none;\n        color: black;\n        width: 130px;\n        height: 40px;\n        margin: 0;\n    }\n\n    .more-panel .el-button--primary:focus {\n        color: teal;\n        background-color: #E8F2F2;\n    }\n\n    .more-panel .el-button--primary:hover {\n        border-radius: 5px;\n        color: teal;\n        background-color: #E8F2F2;\n    }\n\n    .more-panel .el-button--primary:active {\n        color: teal;\n        background-color: #E8F2F2;\n    }\n</style>"
  },
  {
    "path": "front/src/components/index/TopBar.vue",
    "content": "<template>\n    <div class=\"clear-float\">\n        <div class=\"body-image\" v-on:click=\"jumpToIndex\">\n            <img src=\"@/assets/image/Logo.png\"/>\n        </div>\n        <search-panel :tip=\"tip\"  v-on:search=\"searchArticles\"></search-panel>\n        <div class=\"manage\">\n            <img v-if=\"customer.cusAvatarUrl !== ''\" :src=\"customer.cusAvatarUrl\"  v-on:click=\"jumpToSelf\"/>\n            <img v-if=\"customer.cusAvatarUrl === ''\" :src=\"manSrc\"  v-on:click=\"jumpToSelf\"/>\n            <el-button type=\"text\" @click=\"loginOut\">退出登录</el-button>\n        </div>\n    </div>\n</template>\n\n<script>\n    import SearchPanel from '../common/SearchPanel'\n\n    import Man from '../../assets/image/Man.png'\n    import {jumpInCurPage, jumpInNewPage} from \"../../util/PageJump\";\n    import {quitLogin} from \"../../control/Self\";\n\n    export default {\n        name: 'TopBar',\n        props: ['customer'],\n        components: {SearchPanel},\n        methods: {\n            jumpToIndex: function() {\n                jumpInCurPage('/index/');\n            },\n            jumpToSelf: function() {\n               jumpInNewPage('/self/' + this.customer.cusId)\n            },\n            searchArticles: function (message) {\n                jumpInNewPage('/search/' + message )\n                // searchContentByKeyAndTagTypePage(message, 'global', 'test', 0, 10)\n            },\n            loginOut: function () {\n                quitLogin()\n                    .then((response) => {\n                        if (response.data === '退出成功') {\n                            this.$router.push({path: '/port'});\n                        }\n                    })\n            }\n\n        },\n        data: function() {\n            return {\n                tip: '搜索',\n                manSrc: Man,\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .body-image {\n        float: left;\n        height: 40px;\n        margin-top: 5px;\n    }\n\n    .body-image img {\n        height: 30px;\n        width: 130px;\n    }\n\n    .manage {\n        float: right;\n        height: 40px;\n        padding-top: 5px;\n    }\n\n    .manage >>> .el-button {\n        font-size: 16px;\n        height: 40px;\n        float: right;\n    }\n\n    .manage img {\n        width: 30px;\n        height: 30px;\n        /*padding: 5px 10px;*/\n        margin-right: 5px;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/port/LoginPart.vue",
    "content": "<template>\n    <div>\n        <h1>登 录</h1>\n        <el-form :model=\"ruleForm\" status-icon :rules=\"rules\" ref=\"ruleForm\" label-width=\"100px\" class=\"demo-ruleForm\">\n            <el-form-item label=\"用户名\" prop=\"name\">\n                <el-input v-model=\"ruleForm.name\"></el-input>\n            </el-form-item>\n            <el-form-item label=\"密码\" prop=\"pass\">\n                <el-input type=\"password\" v-model=\"ruleForm.pass\" autocomplete=\"off\"></el-input>\n            </el-form-item>\n            <el-form-item>\n                <el-button type=\"primary\" @click=\"cusLogin()\">登录</el-button>\n                <el-button @click=\"cusRegister()\">注册</el-button>\n            </el-form-item>\n        </el-form>\n    </div>\n</template>\n\n<script>\n    import {cusLogin} from \"../../control/Self\";\n    import {jumpInCurPage} from \"../../util/PageJump\";\n\n    export default {\n        name: \"LoginPart.vue\",\n        methods: {\n            cusLogin() {\n                // let data = new FormData();\n                // data.append('cusName', this.ruleForm.name);\n                // data.append('cusPass', this.ruleForm.pass);\n                cusLogin(this.ruleForm.name, this.ruleForm.pass)\n                // this.$axios.post('/api/self/login', data)\n                    .then((response) => {\n                        if (response.data === '登录成功' || response.data === '您已登录') {\n                            this.$message.info(response.data);\n                            // this.$router.push({path: '/index'});\n                            jumpInCurPage('/index')\n                        } else if (response.data === '登录失败') {\n                            this.$message.info(response.data);\n                            this.ruleForm.name = '';\n                            this.ruleForm.pass = '';\n                        }\n                    })\n            },\n            cusRegister() {\n                this.$emit('changePanel');\n            }\n        },\n        data: function () {\n            let validateName = (rule, value, callback) => {\n                if (value === '') {\n                    callback(new Error('请输入用户名'));\n                } else {\n                    callback();\n                }\n            };\n            let validatePass = (rule, value, callback) => {\n                if (value === '') {\n                    callback(new Error('请输入密码'));\n                } else {\n                    callback();\n                }\n            };\n            return {\n                ruleForm: {\n                    name: '',\n                    pass: '',\n                },\n                rules: {\n                    name: [\n                        {\n                            validator: validateName,\n                            trigger: 'blur'\n                        }\n                    ],\n                    pass: [\n                        {\n                            validator: validatePass,\n                            trigger: 'blur'\n                        }\n                    ],\n                }\n            };\n        },\n\n\n    }\n</script>\n\n<style scoped>\n    h1 {\n        margin-left: 100px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/port/RegisterPart.vue",
    "content": "<template>\n    <div>\n        <h1>注 册</h1>\n        <el-form :model=\"ruleForm\" status-icon :rules=\"rules\" ref=\"ruleForm\" label-width=\"100px\" class=\"demo-ruleForm\">\n            <el-form-item label=\"请创建用户名\" prop=\"name\">\n                <el-input v-model=\"ruleForm.name\"></el-input>\n            </el-form-item>\n            <el-form-item label=\"请创建密码\" prop=\"pass\">\n                <el-input type=\"password\" v-model=\"ruleForm.pass\" autocomplete=\"off\"></el-input>\n            </el-form-item>\n            <el-form-item label=\"请确认密码\" prop=\"checkPass\">\n                <el-input type=\"password\" v-model=\"ruleForm.checkPass\" autocomplete=\"off\"></el-input>\n            </el-form-item>\n            <el-form-item>\n                <el-button type=\"primary\" @click=\"cusRegister()\">注册</el-button>\n                <el-button @click=\"cusLogin()\">有账号了, 去登录</el-button>\n            </el-form-item>\n        </el-form>\n    </div>\n</template>\n\n<script>\n    import {cusRegister} from \"../../control/Self\";\n\n    export default {\n        name: \"RegisterPart.vue\",\n        methods: {\n            cusRegister: function() {\n                if (this.ruleForm.pass !== this.ruleForm.checkPass) {\n                    return;\n                }\n\n\n                //\n                // let data = new FormData();\n                // data.append('cusName', this.ruleForm.name);\n                // data.append('cusPass', this.ruleForm.pass);\n                // this.$axios.post('/api/self/register', data);\n                cusRegister(this.ruleForm.name, this.ruleForm.pass)\n                    .then((response) => {\n                        if (response.data === '注册成功') {\n                            this.$message.info(response.data);\n                            this.$emit('changePanel');\n                        } else {\n                            this.$message.info(response.data);\n                            this.ruleForm.name = '';\n                            this.ruleForm.pass = '';\n                            this.ruleForm.checkPass = '';\n                        }\n                    })\n            },\n            cusLogin: function () {\n                this.$emit('changePanel');\n            }\n        },\n        data: function () {\n            let validateName = (rule, value, callback) => {\n                if (value === '') {\n                    callback(new Error('请输入用户名'));\n                } else {\n                    callback();\n                }\n            };\n            let validatePass = (rule, value, callback) => {\n                if (value === '') {\n                    callback(new Error('请输入密码'));\n                } else {\n                    if (this.ruleForm.checkPass !== '') {\n                        this.$refs.ruleForm.validateField('checkPass');\n                    }\n                    callback();\n                }\n            };\n            let validatePass2 = (rule, value, callback) => {\n                if (value === '') {\n                    callback(new Error('请再次输入密码'));\n                } else if (value !== this.ruleForm.pass) {\n                    callback(new Error('两次输入密码不一致!'));\n                } else {\n                    callback();\n                }\n            };\n            return {\n                ruleForm: {\n                    name: '',\n                    pass: '',\n                    checkPass: ''\n                },\n                rules: {\n                    name: [\n                        {\n                            validator: validateName,\n                            trigger: 'blur'\n                        }\n                    ],\n                    pass: [\n                        {\n                            validator: validatePass,\n                            trigger: 'blur'\n                        }\n                    ],\n                    checkPass: [\n                        {\n                            validator: validatePass2,\n                            trigger: 'blur'\n                        }\n                    ]\n                }\n            };\n        },\n    }\n</script>\n\n<style scoped>\n    h1 {\n        margin-left: 100px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/search/RightMenu.vue",
    "content": "<template>\n    <div>\n        <edit-entrance class=\"edit-entrance\"></edit-entrance>\n        <hot-article :title=\"hotArticle.title\" :hot-articles=\"hotArticle.hotArticles\"></hot-article>\n    </div>\n</template>\n\n\n<script>\n    import EditEntrance from '../common/EditEntrance'\n    import HotArticle from '../common/HotArticle'\n\n    import Logo from '../../assets/image/LOGO.png'\n\n    export default {\n        name: 'RightMenu',\n        components: {\n            EditEntrance, HotArticle\n        },\n        data: function () {\n            return {\n                hotArticle: {\n                    title: '热点新闻',\n                    hotArticles: [\n                        { artId: '1', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '2', artTitle: 'This is the template title of news', artImage: ''},\n                        { artId: '3', artTitle: 'This is the template title of news', artImage: ''},\n                        { artId: '4', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '5', artTitle: 'This is the template title of news', artImage: Logo},\n                        { artId: '6', artTitle: 'This is the template title of news', artImage: Logo},\n                    ]\n                }\n            }\n        }\n    }\n</script>\n\n<style scoped>\n    .edit-entrance {\n        margin-bottom: 10px;\n    }\n</style>\n\n"
  },
  {
    "path": "front/src/components/search/TinyCenter.vue",
    "content": "<template>\n    <div>\n        <tiny-article v-for=\"(tinyArticle, i) in tinyArticles\" :key=\"i\" :tinyArticle=\"tinyArticle\"></tiny-article>\n        <span class=\"bottom-tip\">我也是有底线哒 ~</span>\n    </div>\n</template>\n\n<script>\n    import TinyArticle from \"../common/TinyArticle\";\n    export default {\n        name: \"TinyCenter\",\n        components: {TinyArticle},\n        data: function () {\n            return {\n                tinyArticles: [\n                    {   artId: 1, artTitle: \"即将开启降温模式\",\n                        artAbstract:\"降温降雨天气预报预计今晚到明天我州东北部地区阴天普遍有小雨，高山有雨夹雪和大雾，日平均气温下降4～6℃；州西南部晴转多云，局地间有阴天和零星小雨，气温下降2～4℃。请注意相关防御措施。未来24小时内，各县最低气温1℃～10℃，最高气温10～22℃。\",\n                        artTime:\"2019-11-25T08:35:55.000+0000\", cusName:\"光明网\",\n                        artImage:\"http://p1.pstatp.com/large/pgc-image/Reyxsbp6He2NU3\"\n                    },\n                    {   artId: 2, artTitle: \"即将开启升温模式\",\n                        artAbstract:\"降温降雨天气预报预计今晚到明天我州东北部地区阴天普遍有小雨，高山有雨夹雪和大雾，日平均气温下降4～6℃；州西南部晴转多云，局地间有阴天和零星小雨，气温下降2～4℃。请注意相关防御措施。未来24小时内，各县最低气温1℃～10℃，最高气温10～22℃。\",\n                        artTime:\"2019-11-25T08:35:55.000+0000\", cusName:\"光明网\",\n                        artImage:\"\"\n                    },\n                ],\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n</style>"
  },
  {
    "path": "front/src/components/search/TopBar.vue",
    "content": "<template>\n    <div class=\"clear-float\">\n        <div class=\"body-image\" v-on:click=\"jumpToIndex\">\n            <img src=\"@/assets/image/Logo.png\"/>\n        </div>\n        <search-panel :tip=\"tip\" v-on:search=\"searchArticles\"></search-panel>\n        <div class=\"manage\">\n            <img v-if=\"customer.cusAvatarUrl !== ''\" :src=\"customer.cusAvatarUrl\" v-on:click=\"jumpToSelf\"/>\n            <img v-if=\"customer.cusAvatarUrl === ''\" :src=\"manSrc\" v-on:click=\"jumpToSelf\"/>\n            <el-button type=\"text\" @click=\"loginOut\">退出登录</el-button>\n        </div>\n    </div>\n</template>\n\n<script>\n    import SearchPanel from '../common/SearchPanel'\n\n    import Man from '../../assets/image/Man.png'\n    import {jumpInCurPage, jumpInNewPage} from \"../../util/PageJump\";\n    import {quitLogin} from \"../../control/Self\";\n\n    export default {\n        name: 'TopBar',\n        props: ['customer'],\n        components: {SearchPanel},\n        methods: {\n            jumpToIndex: function() {\n                jumpInCurPage('/index/');\n            },\n            jumpToSelf: function() {\n                jumpInNewPage('/self/' + this.customer.cusId)\n            },\n            searchArticles: function (message) {\n                jumpInCurPage('/search/' + message )\n                // searchContentByKeyAndTagTypePage(message, 'global', 'test', 0, 10)\n            },\n            loginOut: function () {\n                // this.$router.push({path: '/port'});\n                quitLogin()\n                    .then((response) => {\n                        if (response.data === '退出成功') {\n                            this.$router.push({path: '/port'});\n                        }\n                    })\n            }\n\n        },\n        data: function() {\n            return {\n                tip: '搜索',\n                manSrc: Man,\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .body-image {\n        float: left;\n        height: 40px;\n        margin-top: 5px;\n    }\n\n    .body-image img {\n        height: 30px;\n        width: 130px;\n    }\n\n    .manage {\n        float: right;\n        height: 40px;\n        padding-top: 5px;\n    }\n\n    .manage >>> .el-button {\n        font-size: 16px;\n        height: 40px;\n        float: right;\n    }\n\n    .manage img {\n        width: 30px;\n        height: 30px;\n        /*padding: 5px 10px;*/\n        margin-right: 5px;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/components/self/EditorMain.vue",
    "content": "<template>\n    <dark-card>\n        <div :style=\"note\">\n            <!-- 用户信息的显示板 -->\n            <div class=\"customer\">\n                <!-- 头像 -->\n                <div class=\"customer-avatar\"><img :src=\"customer.cusAvatarUrl\"></div>\n                <!-- 信息 -->\n                <div class=\"customer-info\">\n                    <span class=\"customer-info-name\">{{customer.cusName}}</span>\n                    <span class=\"customer-info-style\">{{ customer.cusStyle}}</span>\n                    <el-button class=\"follow\" type=\"primary\" v-if=\"!isFollow\"\n                               :disabled=\"visitor.cusId === customer.cusId\" @click=\"followCustomer\">\n                        +关注</el-button>\n                    <el-button class=\"follow\" type=\"success\" v-if=\"isFollow\"\n                               :disabled=\"visitor.cusId === customer.cusId\" @click=\"followCustomer\">\n                        取消关注</el-button>\n                </div>\n            </div>\n        </div>\n    </dark-card>\n</template>\n\n<script>\n    import DarkCard from '../common/DarkCard'\n    import { setCusFollow} from \"../../control/Self\";\n    export default {\n        name: \"EditorMain\",\n        props: ['customer', 'visitor', 'isFollow'],\n        components: { DarkCard },\n        mounted: function() {\n\n        },\n        methods: {\n            followCustomer: function () {\n                setCusFollow(this.customer.cusId)\n                    .then((response) => {\n                        // alert(response.data);\n                        if (response.data === '关注失败') {\n                            this.isFollow = false;\n                        } else {\n                            this.isFollow = true;\n                        }\n                    })\n            }\n        },\n        data: function () {\n            return {\n                // isFollow: false,\n                note: {\n                    height: '150px',\n                    width: '100%',\n                    position: 'relative',\n                },\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .customer-avatar {\n        height: 150px;\n        width: 150px;\n        float: left;\n        margin-right: 30px;\n    }\n\n    .customer-avatar img {\n        width: 100%;\n    }\n\n    .customer-info {\n        height: 100px;\n        margin-top: 50px;\n        float: left;\n        text-align: left;\n    }\n\n    .customer-info-name {\n        display: block;\n        line-height: 45px;\n        font-size: 30px;\n        font-weight: 600;\n    }\n\n    .customer-info-style {\n        display: block;\n        font-size: 16px;\n        line-height: 25px;\n    }\n\n    .el-button {\n        height: 25px;\n        width: 60px;\n        padding: 0px;\n        font-size: 10pt;\n        border-radius: 1px;\n        display: block;\n    }\n</style>"
  },
  {
    "path": "front/src/components/self/RightMenu.vue",
    "content": "<template>\n    <div>\n        <div class=\"achievement-panel\">\n            <div class=\"follower-followee\">\n                <div class=\"follow\" >\n                    <span class=\"follow-num\">{{info.followNum}}</span>\n                    <span class=\"follow-tip\">关注了</span>\n                </div>\n                <div  class=\"follow\">\n                    <span class=\"follow-num\">{{info.fanNum}}</span>\n                    <span class=\"follow-tip\">粉丝</span>\n                </div>\n            </div>\n            <hr>\n            <h2>个人成就</h2>\n            <div class=\"achievement\">\n                <i class=\"el-icon-star-on icon\"></i>\n                <span>阅读了</span>\n                <span class=\"achievement-num\">{{info.readNum}}</span>\n                <span>篇文章 </span>\n            </div>\n            <div class=\"achievement\">\n                <i class=\"el-icon-edit icon\"></i>\n                <span>发表了</span>\n                <span class=\"achievement-num\">{{info.artEditNum}}</span>\n                <span>篇文章</span>\n            </div>\n            <div class=\"achievement\">\n                <i class=\"el-icon-star-on icon\"></i>\n                <span>编辑了</span>\n                <span class=\"achievement-num\">{{info.comEditNum + info.repEditNum}}</span>\n                <span>次评论 </span>\n            </div>\n        </div>\n    </div>\n</template>\n\n<script>\n    export default {\n        name: \"RightMenu\",\n        props: [\"info\"],\n\n\n    }\n</script>\n\n<style scoped>\n    .achievement-panel {\n        padding: 15px;\n        height: 200px;\n        background: #f4f5f6;\n    }\n\n    .follower-followee {\n        display: flex;\n    }\n\n    .follow {\n        flex: 1;\n    }\n\n    .follow-num {\n        display: block;\n        font-size: 20px;\n        font-weight: 500;\n    }\n\n    .follow-tip {\n        display: block;\n    }\n\n    h2 {\n        margin: 10px 0px;\n    }\n\n    .icon {\n        margin-right: 10px\n    }\n\n    .achievement {\n        text-align: left;\n    }\n\n    .achievement-num {\n        font-size: 20px;\n        font-weight: 500;\n        margin-right: 5px;\n        margin-left: 5px;\n    }\n</style>"
  },
  {
    "path": "front/src/components/self/TinyCenter.vue",
    "content": "<template>\n    <div>\n        <float-card class=\"float-card clear-float\" v-for=\"(customerDynamic, i) in customerDynamics\" :key=\"i\" >\n            <div class=\"span-div\">\n                <span class=\"span-a\">{{customerDynamic.cusFrom.cusName}}</span>\n                <span class=\"span-b\">{{transBehaviorCodeToWord(customerDynamic.cbrBehavior)}}</span>\n            </div>\n            <!-- 文章处理 -->\n            <div v-if=\"customerDynamic.cbrType === 1\" class=\"art-han\">\n                <div class=\"image\" v-if=\"customerDynamic.article.artImageUrl !== ''\">\n                    <img :src=\"customerDynamic.article.artImageUrl\" >\n                </div>\n                <div class=\"word\" :class=\"[customerDynamic.article.artImageUrl !== '' ? tinyArt : tinyArtWide]\">\n                    <div class=\"title\" @click=\"jumpToArticle(customerDynamic.article.artId)\">{{ customerDynamic.article.artTitle }}</div>\n                    <div class=\"info\">\n                        <span class=\"type\">{{ customerDynamic.article.artType}}</span>\n                        <span class=\"customer\" @click=\"jumpToCustomer(customerDynamic.cusTo.cusId)\">{{ customerDynamic.cusTo.cusName }}</span>\n                        <span>{{ date(customerDynamic.article.artTime) }}</span>\n                    </div>\n                </div>\n            </div>\n            <!-- 评论处理 -->\n            <div v-if=\"customerDynamic.cbrType === 2\" class=\"com-han\">\n                <div class=\"com clear-float\">\n                    <div class=\"title\" @click=\"jumpToArticle(customerDynamic.cbrArtId)\">{{ customerDynamic.article.artTitle }}</div>\n                    <div class=\"com-content\"  v-html=\"customerDynamic.comment.comContent\"></div>\n                    <div class=\"info\">\n                        <span class=\"type\">{{ customerDynamic.article.artType}}</span>\n                        <span class=\"customer\" @click=\"jumpToCustomer(customerDynamic.cusTo.cusId)\">{{ customerDynamic.cusTo.cusName }}</span>\n                        <span>{{ date(customerDynamic.comment.comTime) }}</span>\n                    </div>\n                </div>\n            </div>\n            <!-- 回复处理 -->\n            <div v-if=\"customerDynamic.cbrType === 3\" class=\"rep-han\">\n                <div class=\"rep clear-float\">\n                    <div class=\"title\" @click=\"jumpToArticle(customerDynamic.cbrArtId)\">{{ customerDynamic.article.artTitle }}</div>\n                    <div class=\"com-content\" v-html=\"customerDynamic.reply.repContent\"></div>\n                    <div class=\"info\">\n                        <span class=\"type\">{{ customerDynamic.article.artType}}</span>\n                        <span class=\"customer\" @click=\"jumpToCustomer(customerDynamic.cusTo.cusId)\">{{ customerDynamic.cusTo.cusName }}</span>\n                        <span>{{ date(customerDynamic.reply.repTime) }}</span>\n                    </div>\n                </div>\n            </div>\n            <!-- 用户关注 -->\n            <div v-if=\"customerDynamic.cbrType === 0\" class=\"fol-han\">\n                <div class=\"name-time\">\n                    <div class=\"title\" @click=\"jumpToCustomer(customerDynamic.cusTo.cusId)\">{{ customerDynamic.cusTo.cusName }}</div>\n                    <div class=\"info\">\n                        <span>{{ date(customerDynamic.cbrTime) }}</span>\n                    </div>\n                </div>\n            </div>\n\n        </float-card>>\n\n        <span class=\"bottom-tip\">我也是有底线哒 ~</span>\n    </div>\n</template>\n\n<script>\n    // import TinyArticle from \"../common/TinyArticle\";\n    import {jumpInNewPage} from \"../../util/PageJump\";\n    import {transUTCtoLocal} from \"../../util/TimeHandler\";\n    import FloatCard from \"../common/FloatCard\";\n    export default {\n        name: \"TinyCenter\",\n        components: {FloatCard},\n        // components: {TinyArticle},\n        props: ['customerDynamics', 'ownerCustomer'],\n        methods: {\n            /**\n             * 跳转至文章页面\n             * @param artId\n             */\n            jumpToArticle: function (artId) {\n                jumpInNewPage('/article/' + artId);\n            },\n\n            /**\n             * 跳转至作者用户页面\n             * @param cusId\n             */\n            jumpToCustomer: function (cusId) {\n                jumpInNewPage('/self/' + cusId);\n            },\n\n            date: function (time) {\n                return transUTCtoLocal(time);\n            },\n\n            transBehaviorCodeToWord: function (code) {\n                if (code === 1) {\n                    return '编辑了文章';\n                } else if (code === 3) {\n                    return '点赞了文章';\n                } else if (code === 4) {\n                    return '点踩了文章';\n                } else if (code === 5 || code === 8) {\n                    return '评论了文章';\n                } else if (code === 11) {\n                    return '关注了用户'\n                }\n            }\n        },\n        data: function () {\n            return {\n                tinyArt: 'tiny-art',\n                tinyArtWide: 'tiny-art-wide',\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .span-div {\n        display: flex;\n        height: 40px;\n        font-size: 20px;\n        color: #008080;\n    }\n\n    .span-a {\n        margin-right: 10px;\n    }\n\n    .span-b {\n        /*margin-right: 10px;*/\n    }\n\n    .bottom-tip {\n        color: #888888;\n    }\n\n    .float-card {\n        margin-bottom: 15px;\n    }\n\n    .image img {\n        float: left;\n        width: 27%;\n        height: 120px;\n        margin-right: 3%;\n    }\n\n    .word {\n        float: left;\n        height: 120px;\n        position: relative;\n    }\n\n    .com {\n        float: left;\n        /*height: 120px;*/\n        position: relative;\n    }\n\n    .rep {\n        float: left;\n        /*height: 120px;*/\n        position: relative;\n    }\n\n    .tiny-art {\n        width: 70%;\n    }\n\n    .tiny-art-wide {\n        width: 100%;\n    }\n\n    .title {\n        height: 60px;\n        line-height: 30px;\n        font-size: 18pt;\n        overflow: hidden;\n        text-align: left;\n        margin-bottom: 5px;\n        font-weight: 800;\n    }\n\n    .title:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n\n    .description {\n        height: 20px;\n        line-height: 20px;\n        overflow: hidden;\n        text-align: left;\n        color: #888888;\n    }\n\n    .info {\n        text-align: left;\n        font-size: 14px;\n        position: absolute;\n        bottom: 0;\n        color: #888888;\n    }\n\n    .info :first-child {\n        font-weight: 400;\n    }\n\n    .com-han .info {\n        text-align: left;\n        font-size: 14px;\n        position: static;\n        /*bottom: 0;*/\n        color: #888888;\n        margin-top: 10px;\n    }\n\n    .rep-han .info {\n        text-align: left;\n        font-size: 14px;\n        position: static;\n        /*bottom: 0;*/\n        color: #888888;\n        margin-top: 10px;\n    }\n\n    .fol-han .info {\n        text-align: left;\n        font-size: 14px;\n        position: static;\n        /*bottom: 0;*/\n        color: #888888;\n    }\n\n    .fol-han .title {\n        height: 30px;\n        line-height: 30px;\n        font-size: 18pt;\n        overflow: hidden;\n        text-align: left;\n        margin-bottom: 5px;\n        font-weight: 800;\n    }\n\n\n    .customer {\n        margin-right: 5px;\n    }\n\n    .customer:hover {\n        color: #339999;\n        cursor: pointer;\n    }\n\n    .com-content {\n        text-align: left;\n        /*height: 30px;*/\n        /*overflow: hidden;*/\n    }\n\n    .com-content >>> p {\n        /*margin: 0px 0 0 0;*/\n        margin: 0;\n        /*line-height: 30px;*/\n    }\n\n    .type {\n        margin-right: 10px;\n        border: 1px;\n        border-style: solid;\n        border-radius: 3px;\n        color: darkred;\n    }\n</style>"
  },
  {
    "path": "front/src/components/self/TopBar.vue",
    "content": "<template>\n    <div class=\"clear-float\">\n        <div class=\"body-image\"  v-on:click=\"jumpToIndex\">\n            <img src=\"@/assets/image/Logo.png\"/>\n        </div>\n        <search-panel :tip=\"tip\"  v-on:search=\"searchArticles\"></search-panel>\n        <div class=\"manage\">\n            <img v-if=\"customer.cusAvatarUrl !== ''\" :src=\"customer.cusAvatarUrl\" v-on:click=\"jumpToSelf\"/>\n            <img v-if=\"customer.cusAvatarUrl === ''\" :src=\"manSrc\" v-on:click=\"jumpToSelf\"/>\n            <el-button type=\"text\" @click=\"loginOut\">退出登录</el-button>\n        </div>\n    </div>\n</template>\n\n<script>\n    import SearchPanel from '../common/SearchPanel'\n    import Man from '../../assets/image/Man.png'\n    import {jumpInCurPage, jumpInNewPage} from \"../../util/PageJump\";\n    import {quitLogin} from \"../../control/Self\";\n\n    export default {\n        name: 'TopBar',\n        props: ['customer'],\n        components: {SearchPanel},\n        methods: {\n            jumpToIndex: function() {\n                jumpInCurPage('/index/');\n            },\n            jumpToSelf: function() {\n                jumpInNewPage('/self/' + this.customer.cusId)\n            },\n            searchArticles: function (message) {\n                jumpInNewPage('/search/' + message )\n                // searchContentByKeyAndTagTypePage(message, 'global', 'test', 0, 10)\n            },\n            loginOut: function () {\n                quitLogin()\n                    .then((response) => {\n                        if (response.data === '退出成功') {\n                            this.$router.push({path: '/port'});\n                        }\n                    })\n            }\n\n        },\n        data: function() {\n            return {\n                tip: '搜索',\n                manSrc: Man,\n            }\n        }\n    }\n</script>\n\n<style scoped>\n\n    .body-image {\n        float: left;\n        height: 40px;\n        margin-top: 5px;\n    }\n\n    .body-image img {\n        height: 30px;\n        width: 130px;\n    }\n\n    .manage {\n        float: right;\n        height: 40px;\n        padding-top: 5px;\n    }\n\n    .manage >>> .el-button {\n        font-size: 16px;\n        height: 40px;\n        float: right;\n    }\n\n    .manage img {\n        width: 30px;\n        height: 30px;\n        /*padding: 5px 10px;*/\n        margin-right: 5px;\n    }\n\n</style>\n"
  },
  {
    "path": "front/src/control/Discuss.js",
    "content": "import axios from 'axios'\n\nlet base = '/api/discuss/';\n\nexport function getComList(artId) {\n    let config = {\n        params: {\n            artId: artId,\n        }\n    };\n    return axios.get(base + 'page', config);\n}\n\nexport function addNewCom(comment) {\n    return axios.post(base + 'com', comment)\n}\n\nexport function cusAddReply(reply) {\n    return axios.post(base + 'rep', reply)\n}\n\n// export function cusComPreference(comId, preference) {\n//     return axios.get('/api/discuss/precom?comId=' + comId + '&preference=' + preference)\n// }\n//\n// export function cusRepPreference(repId, preference) {\n//     return axios.get('/api/discuss/prerep?repId=' + repId + '&preference=' + preference)\n// }"
  },
  {
    "path": "front/src/control/Edit.js",
    "content": "import axios from 'axios'\n\nlet base = '/api/edit/';\n\nexport function addNewArt(article) {\n    return axios.post(base + 'add', article);\n}\n"
  },
  {
    "path": "front/src/control/Load.js",
    "content": "import axios from 'axios'\n\nlet base = '/api/load/';\n\nexport function getArtTypes() {\n    return axios.get(base + 'type');\n}\n\nexport function getTinyArtOnePageByType(artType, page, pageSize) {\n    let config = {\n        params: {\n            artType: artType,\n            page: page,\n            pageSize: pageSize\n        }\n    };\n    return axios.get(base + 'tiny', config);\n}\n\nexport function getHotArtOnePage(page, pageSize) {\n    let config = {\n        params: {\n            page: page,\n            pageSize: pageSize\n        }\n    };\n\n    return axios.get(base + 'hot', config);\n}\n\nexport function getFullArt(artId) {\n    let config = {\n        params: {\n            artId: artId\n        }\n    };\n    return axios.get(base + 'main', config);\n}\n\nexport function setArtPreference(artId, type) {\n    let config = {\n        params: {\n            artId: artId,\n            type: type\n        }\n    };\n    return axios.get(base + 'prefer', config);\n}"
  },
  {
    "path": "front/src/control/Search.js",
    "content": "import axios from 'axios'\n\nlet base = '/api/search/';\n\nexport function searchContentSimple(key, page, pageSize) {\n    let config = {\n        params: {\n            key: key,\n            page: page,\n            pageSize: pageSize\n        }\n    };\n    return axios.get(base + 'simple', config);\n}\n\n// export function searchContentByKeyAndTagTypePage(key, tag, type, page, pageSize) {\n//     return axios.get('/api/search/key?key=' + key + '&tag=' + tag + '&type=' + type + '&page=' + page + '&pageSize=' + pageSize)\n// }"
  },
  {
    "path": "front/src/control/Self.js",
    "content": "import axios from 'axios'\n\nlet base = '/api/self/';\n\nexport function cusLogin(cusName, cusPass) {\n    let data = new FormData();\n    data.append('cusName', cusName);\n    data.append('cusPass', cusPass);\n    return axios.post(base + 'login', data);\n}\n\nexport function quitLogin() {\n    return axios.get(base + 'quit');\n}\n\nexport function cusRegister(cusName, cusPass) {\n    let data = new FormData();\n    data.append('cusName', cusName);\n    data.append('cusPass', cusPass);\n    return axios.post(base + 'register', data)\n}\n\nexport function getCusBasicInfo(cusId) {\n    let config = {\n        params: {\n            cusId: cusId\n        }\n    };\n    return axios.get(base + 'basic', config)\n}\n\nexport function setCusBasicInfo(customer) {\n    let config = {\n        params: {\n            customer: customer\n        }\n    };\n    return axios.get(base + 'modify', config);\n}\n\nexport function setCusFollow(cusId) {\n    let config = {\n        params: {\n            cusId: cusId\n        }\n    };\n    return axios.get(base + 'follow', config);\n}\n\n\nexport function getCusFeatureInfo(cusId) {\n    let config = {\n        params: {\n            cusId: cusId\n        }\n    };\n    return axios.get(base + 'feature', config);\n}\n\nexport function getCusSelfDynamic(cusId, page, pageSize) {\n    let config = {\n        params: {\n            cusId: cusId,\n            page: page,\n            pageSize: pageSize\n        }\n    };\n    return axios.get(base + 'dynamic', config);\n}\n\nexport function checkCusFollow(cusId) {\n    let config = {\n        params: {\n            cusId: cusId\n        }\n    };\n    return axios.get(base + 'chefollow', config)\n}"
  },
  {
    "path": "front/src/main.js",
    "content": "import Vue from 'vue'\nimport './plugins/axios'\nimport App from './App.vue'\nimport ElementUI from 'element-ui'\n// import VueBlu from 'vue-blu'\nimport locale from 'element-ui/lib/locale/lang/zh-CN'\nimport './styles.scss'\n// import 'vue-blu/dist/css/vue-blu.min.css'\nimport router from './router'\n\nVue.use(ElementUI, { locale });\n// Vue.use(VueBlu);\n\nVue.config.productionTip = false;\n\nnew Vue({\n  router,\n  render: h => h(App)\n}).$mount('#app');\n"
  },
  {
    "path": "front/src/plugins/axios.js",
    "content": "\"use strict\";\n\nimport Vue from 'vue';\nimport axios from \"axios\";\n\n// Full config:  https://github.com/axios/axios#request-config\n// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';\n// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;\n// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';\n\nlet config = {\n  // baseURL: process.env.baseURL || process.env.apiUrl || \"\"\n  // timeout: 60 * 1000, // Timeout\n  // withCredentials: true, // Check cross-site Access-Control\n};\n\nconst _axios = axios.create(config);\n\n_axios.interceptors.request.use(\n  function(config) {\n    // Do something before request is sent\n    return config;\n  },\n  function(error) {\n    // Do something with request error\n    return Promise.reject(error);\n  }\n);\n\n// Add a response interceptor\n_axios.interceptors.response.use(\n  function(response) {\n    // Do something with response data\n    return response;\n  },\n  function(error) {\n    // Do something with response error\n    return Promise.reject(error);\n  }\n);\n\nPlugin.install = function(Vue) {\n  Vue.axios = _axios;\n  window.axios = _axios;\n  Object.defineProperties(Vue.prototype, {\n    axios: {\n      get() {\n        return _axios;\n      }\n    },\n    $axios: {\n      get() {\n        return _axios;\n      }\n    },\n  });\n};\n\nVue.use(Plugin)\n\nexport default Plugin;\n"
  },
  {
    "path": "front/src/router/index.js",
    "content": "import Vue from 'vue'\nimport VueRouter from 'vue-router'\n// import Home from '../views/Home.vue'\n\n\nimport IndexView from '../views/IndexView'\nimport SearchView from '../views/SearchView'\nimport ArticleView from \"../views/ArticleView\"\nimport SelfView from '../views/SelfView'\nimport PortView from \"../views/PortView\";\nimport EditView from \"../views/EditView\";\n\nVue.use(VueRouter);\n\nconst routes = [\n  {\n    path: '/',\n    name: 'PortView',\n    component: PortView\n  },\n  {\n    path: '/index',\n    name: 'IndexView',\n    component: IndexView\n  },\n  {\n    path: '/search/:key',\n    name: 'SearchView',\n    component: SearchView\n  },\n  {\n    path: '/article/:artId',\n    name: 'ArticleView',\n    component: ArticleView\n  },\n  {\n    path: '/self/:cusId',\n    name: 'SelfView',\n    component: SelfView\n  },\n  {\n    path: '/port',\n    name: 'PortView',\n    component: PortView\n  },\n  {\n    path: '/edit',\n    name: 'EditView',\n    component: EditView\n  }\n\n  // {\n  //   path: '/about',\n  //   name: 'about',\n  //   // route level code-splitting\n  //   // this generates a separate chunk (about.[hash].js) for this route\n  //   // which is lazy-loaded when the route is visited.\n  //   component: () => import(/* webpackChunkName: \"about\" */ '../views/About.vue')\n  // }\n];\n\nconst router = new VueRouter({\n  mode: 'history',\n  base: process.env.BASE_URL,\n  routes\n});\n\nexport default router\n"
  },
  {
    "path": "front/src/styles.scss",
    "content": "/* theme color */\n$--color-primary: teal;\n\n/* icon font path, required */\n$--font-path: '~element-ui/lib/theme-chalk/fonts';\n\n@import \"~element-ui/packages/theme-chalk/src/index\";\n"
  },
  {
    "path": "front/src/util/PageJump.js",
    "content": "import router from '@/router/index.js'\n\nexport function jumpInCurPage(road) {\n    let route = router.resolve(road);\n    window.open(route.href, '_self');\n}\n\nexport function jumpInNewPage(road) {\n    let route = router.resolve(road);\n    window.open(route.href, '_blank');\n}"
  },
  {
    "path": "front/src/util/TimeHandler.js",
    "content": "export function transUTCtoLocal(time) {\n    return new Date(Date.parse(time)).toLocaleString();\n}"
  },
  {
    "path": "front/src/views/About.vue",
    "content": "<template>\n  <div class=\"about\">\n    <h1>This is an about page</h1>\n  </div>\n</template>\n"
  },
  {
    "path": "front/src/views/ArticleView.vue",
    "content": "<template>\n    <div>\n        <header><top-bar class=\"top-bar\" :customer=\"customer\"></top-bar></header>\n        <main>\n            <article>\n                <article-main :articleMain=\"artMain\"></article-main>\n                <comment-reply-main :comments=\"comments\" :customer=\"customer\" @quickShow=\"quickShow\"></comment-reply-main>\n            </article>\n            <aside>\n                <editor-brief class=\"editor-brief\" :articleAuthor=\"artMain.customer\" :artSelfStatus=\"artMain.cusArtBehavior\" :customer=\"customer\" v-on:editor=\"jumpToCustomer\"></editor-brief>\n                <edit-entrance class=\"edit-entrance\"></edit-entrance>\n                <hot-article :title=\"page.hotTitle\" :hot-articles=\"hotArticles\"\n                             v-on:refresh=\"refreshHot\" v-on:jump=\"jumpToArticle\"></hot-article>\n            </aside>\n        </main>\n    </div>\n</template>\n\n<script>\n    import TopBar from \"../components/article/TopBar\";\n    import CommentReplyMain from \"../components/article/CommentReplyCenter\";\n    import ArticleMain from \"../components/article/ArticleCenter\";\n    import EditorBrief from \"../components/common/EditorBrief\";\n    import EditEntrance from \"../components/common/EditEntrance\";\n    import HotArticle from \"../components/common/HotArticle\";\n\n    import Logo from '../assets/image/Logo.png'\n    import {getFullArt, getHotArtOnePage} from \"../control/Load\";\n    import {getCusBasicInfo} from \"../control/Self\";\n    import {getComList} from \"../control/Discuss\";\n    import {jumpInCurPage, jumpInNewPage} from \"../util/PageJump\";\n\n    export default {\n        name: \"ArticleView\",\n        components: {HotArticle, EditEntrance, EditorBrief, ArticleMain, CommentReplyMain, TopBar},\n        mounted: function() {\n            let artId = this.$route.params.artId;\n            getCusBasicInfo(0)\n                .then((response) => {\n                    if (response.data) {\n                        this.customer = response.data;\n                    } else {\n                        // this.$router.push({path: '/port'});\n                        jumpInCurPage('/port');\n                    }\n                });\n            getFullArt(artId)\n                .then((response) => {\n                    this.artMain = response.data;\n                });\n            getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                .then((response) => {\n                    this.hotArticles = response.data;\n                });\n            getComList(artId)\n                .then((response) => {\n                    this.comments = response.data;\n                });\n            window.scrollTo(0, 0);\n        },\n        methods: {\n            /**\n             * 刷新热点新闻\n             */\n            refreshHot: function () {\n                if (this.page.hotPage > 3) {\n                    this.page.hotPage = 0;\n                } else {\n                    this.page.hotPage += 1;\n                }\n                getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                    .then((response) => {\n                        this.hotArticles = response.data;\n                    })\n                    .catch(() => {\n                        this.$message.info(\"抱歉, 发生了点故障\");\n                    });\n            },\n\n            /**\n             * 跳转至文章页面\n             * @param artId\n             */\n            jumpToArticle: function (artId) {\n                jumpInNewPage('/article/' + artId);\n            },\n\n            jumpToCustomer: function (cusId) {\n                jumpInNewPage('/self/' + cusId);\n            },\n\n            quickShow: function () {\n                let artId = this.$route.params.artId;\n                getComList(artId)\n                    .then((response) => {\n                        this.comments = response.data;\n                    })\n            }\n        },\n        data: function () {\n            return {\n                page: {\n                    hotTitle: '热点新闻',\n                    hotPage: 0,\n                    hotPageSize: 6,\n                    // comPage: 0,\n                    // comPageSize: 4\n                },\n                customer: {\n\n                },\n                artMain: {\n\n                },\n                hotArticles: [\n                    { artId: '1', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '2', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '3', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '4', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '5', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '6', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                ],\n                comments: [\n\n                ]\n            }\n        }\n    }\n</script>\n\n<style scoped src=\"../assets/css/Narrow.css\"></style>\n<style scoped>\n    .editor-brief, .edit-entrance {\n        margin-bottom: 10px;\n    }\n\n\n</style>"
  },
  {
    "path": "front/src/views/EditView.vue",
    "content": "<template>\n    <div>\n        <header>\n            <top-bar class=\"top-bar\" :customer=\"customer\"></top-bar>\n        </header>\n        <main>\n            <!--<h2 class=\"title\">编辑</h2>-->\n            <el-form ref=\"form\" :model=\"form\" label-width=\"80px\">\n\n                <el-form-item class=\"title-panel\">\n                    <el-col :span=\"16\">\n                        <el-form-item label=\"标题\">\n                            <el-input v-model=\"form.name\"></el-input>\n                        </el-form-item>\n                    </el-col>\n                    <el-col :span=\"6\">\n                        <el-form-item label=\"文章类别\">\n                            <el-select v-model=\"form.type\" placeholder=\"文章类别\">\n                                <el-option label=\"社会\" value=\"社会\"></el-option>\n                                <el-option label=\"军事\" value=\"军事\"></el-option>\n                                <el-option label=\"财经\" value=\"财经\"></el-option>\n                                <el-option label=\"旅游\" value=\"旅游\"></el-option>\n                                <el-option label=\"养生\" value=\"养生\"></el-option>\n                                <el-option label=\"游戏\" value=\"游戏\"></el-option>\n\n                                <el-option label=\"娱乐\" value=\"娱乐\"></el-option>\n                                <el-option label=\"体育\" value=\"体育\"></el-option>\n                                <el-option label=\"国际\" value=\"国际\"></el-option>\n                                <el-option label=\"探索\" value=\"探索\"></el-option>\n                                <el-option label=\"故事\" value=\"故事\"></el-option>\n                                <el-option label=\"历史\" value=\"历史\"></el-option>\n\n                                <el-option label=\"科技\" value=\"科技\"></el-option>\n                                <el-option label=\"汽车\" value=\"汽车\"></el-option>\n                                <el-option label=\"时尚\" value=\"时尚\"></el-option>\n                                <el-option label=\"育儿\" value=\"育儿\"></el-option>\n                                <el-option label=\"美文\" value=\"美文\"></el-option>\n                                <el-option label=\"美食\" value=\"美食\"></el-option>\n                            </el-select>\n                        </el-form-item>\n                    </el-col>\n                </el-form-item>\n\n                <el-form-item class=\"edit-panel\">\n                    <div ref=\"toolbar\" class=\"toolbar\"></div>\n                    <div ref=\"textplace\" class=\"textplace\"></div>\n                </el-form-item>\n                <el-form-item class=\"buttom-panel\">\n                    <el-button type=\"primary\" @click=\"onSubmit\">创建新闻</el-button>\n                    <el-button @click=\"cancelCreate\">取消</el-button>\n                </el-form-item>\n            </el-form>\n        </main>\n    </div>\n</template>\n\n\n\n\n<script>\n    import TopBar from \"../components/edit/TopBar\";\n    import {getCusBasicInfo} from \"../control/Self\";\n    import {jumpInCurPage} from \"../util/PageJump\";\n    import WangEditor from 'wangeditor'\n    import {addNewArt} from \"../control/Edit\";\n    export default {\n        name: \"EditView.vue\",\n        components: {TopBar},\n        mounted: function() {\n            getCusBasicInfo(0)\n                .then((response) => {\n                    if (response.data) {\n                        this.customer = response.data;\n                    } else {\n                        // this.$router.push({path: '/port'});\n                        jumpInCurPage('/port');\n                    }\n                });\n\n            let editor = new WangEditor(this.$refs.toolbar, this.$refs.textplace);\n            this.editor = editor;\n            editor.customConfig.onchange = (html) => {\n                this.message = html;\n            };\n            editor.customConfig.menus = this.menus;\n            editor.create();\n\n            window.scrollTo(0, 0);\n        },\n        methods: {\n            onSubmit() {\n                // this.$message.info(this.message);\n                let article = {\n                    artTitle: this.form.name,\n                    artContent: this.message,\n                    artCusId: this.customer.cusId,\n                    artType: this.form.type,\n                    artImageUrl: ''\n                };\n                // this.$message.info(article.artTitle)\n                addNewArt(article)\n                    .then(\n                        (response) => {\n                            if (response.data !== 0) {\n                                this.$message.info(\"文章添加成功\");\n                                jumpInCurPage('/article/' + response.data)\n                            } else {\n                                this.$message.info(\"文章添加失败\");\n                            }\n                        }\n                    )\n            },\n            cancelCreate: function () {\n                jumpInCurPage('/index')\n            }\n        },\n        data: function () {\n            return {\n                customer: {\n\n                },\n                message: 'message',\n                menus: [\n                    'head',  // 标题\n                    'bold',  // 粗体\n                    // 'fontSize',  // 字号\n                    // 'fontName',  // 字体\n                    'italic',  // 斜体\n                    'underline',  // 下划线\n                    'strikeThrough',  // 删除线\n                    // 'foreColor',  // 文字颜色\n                    // 'backColor',  // 背景颜色\n                    // 'link',  // 插入链接\n                    'list',  // 列表\n                    'justify',  // 对齐方式\n                    // 'quote',  // 引用\n                    'emoticon',  // 表情\n                    'image',  // 插入图片\n                    'table',  // 表格\n                    // 'video',  // 插入视频\n                    // 'code',  // 插入代码\n                    'undo',  // 撤销\n                    'redo'  // 重复\n                ],\n                form: {\n                    name: '',\n                    type: '',\n                }\n            }\n        }\n    }\n</script>\n\n\n<style scoped src=\"../assets/css/Narrow.css\"></style>\n<style scoped>\n\n    .title {\n        display: flex;\n    }\n\n    .toolbar {\n        height: 50px;\n        border: 0 solid #f1f1f1;\n        background-color:#f1f1f1;\n        position: relative;\n    }\n\n    .textplace {\n        height: 600px;\n        border: 1px solid #f1f1f1;\n        text-align: left;\n        margin-bottom: 40px;\n        /*overflow: hidden;*/\n    }\n\n    .textplace >>> .w-e-text {\n        padding: 5px 10px;\n    }\n\n    .textplace >>> .w-e-text p {\n        margin: 0;\n        line-height: 20px;\n    }\n\n    /*.title-panel.el-form-item >>> .el-form-item__content {*/\n    /*    margin-left: 20px !important;*/\n    /*}*/\n\n    .edit-panel.el-form-item >>> .el-form-item__content {\n        margin: 0 !important;\n    }\n\n    .buttom-panel.el-form-item >>> .el-form-item__content {\n        margin: 0 !important;\n    }\n\n\n</style>"
  },
  {
    "path": "front/src/views/Home.vue",
    "content": "<template>\n  <div class=\"home\">\n    <img alt=\"Vue logo\" src=\"../assets/logo.png\">\n    <HelloWorld msg=\"Welcome to Your Vue.js App\"/>\n  </div>\n</template>\n\n<script>\n// @ is an alias to /src\nimport HelloWorld from '../components/app/HelloWorld.vue'\n\nexport default {\n  name: 'home',\n  components: {\n    HelloWorld\n  }\n}\n</script>\n"
  },
  {
    "path": "front/src/views/IndexView.vue",
    "content": "<template>\n    <div>\n        <header>\n            <top-bar class=\"top-bar\" :customer=\"customer\"></top-bar>\n        </header>\n        <main>\n            <nav>\n                <left-menu :curIndex=\"page.menuCurIndex\" :majorLength=\"page.menuMajorLen\" :tip=\"page.menuTip\"\n                                 :artClassList=\"artTypes\" v-on:changeCurIndex=\"changeCurIndex\"></left-menu>\n            </nav>\n            <article>\n                <tiny-article v-for=\"(tinyArticle, i) in tinyArticles\" :key=\"i\" :tinyArticle=\"tinyArticle\"\n                              v-on:jump=\"jumpToArticle\" v-on:editor=\"jumpToCustomer\"></tiny-article>\n            </article>\n            <aside>\n                <edit-entrance class=\"edit-entrance\"></edit-entrance>\n                <hot-article :title=\"page.hotTitle\" :hot-articles=\"hotArticles\"\n                             v-on:refresh=\"refreshHot\" v-on:jump=\"jumpToArticle\"></hot-article>\n            </aside>\n        </main>\n    </div>\n</template>\n\n<script>\n    import TopBar from '../components/index/TopBar'\n    import LeftMenu from \"../components/index/LeftMenu\"\n    import TinyArticle from '../components/common/TinyArticle'\n    import EditEntrance from \"../components/common/EditEntrance\";\n    import HotArticle from \"../components/common/HotArticle\";\n\n    import Logo from '../assets/image/Logo.png'\n    import {getArtTypes, getHotArtOnePage, getTinyArtOnePageByType} from \"../control/Load\";\n    import {getCusBasicInfo} from \"../control/Self\";\n    import {jumpInCurPage, jumpInNewPage} from \"../util/PageJump\";\n\n    export default {\n        name: 'IndexView',\n        components: {HotArticle, EditEntrance, TinyArticle, TopBar, LeftMenu},\n        mounted: function () {\n            window.addEventListener('scroll', this.getMoreTinyArt, false);\n            getCusBasicInfo(0)\n                .then((response) => {\n                    if (response.data) {\n                        this.customer = response.data;\n                    } else {\n                        // this.$router.push({path: '/port'});\n                        jumpInCurPage('/port');\n                    }\n\n                });\n            getArtTypes()\n                .then((response) => {\n                    this.artTypes = response.data;\n                })\n                .then(() => {\n                    getTinyArtOnePageByType('综合', this.page.tinyPage, this.page.tinyPageSize)\n                        .then((response) => {\n                            this.tinyArticles = response.data;\n                        });\n                    getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                        .then((response) => {\n                            this.hotArticles = response.data;\n                        });\n                });\n            window.scrollTo(0, 0);\n        },\n        methods: {\n            /**\n             * 如果选中的类别超过了 this.leftMenu.majorLength 的限制, 即属于二级类别,\n             * 则调换 选中的类别 与 一级类别中最后一个类别 在数组中的位置.\n             *\n             * @param index 选中的类别下标\n             */\n            changeCurIndex: function (index) {\n                if (index >= this.page.menuMajorLen) {\n                    this.page.menuCurIndex = this.page.menuMajorLen - 1;\n                    let median = this.artTypes[this.page.menuMajorLen - 1];\n                    this.artTypes[this.page.menuMajorLen - 1] = this.artTypes[index];\n                    this.artTypes[index] = median;\n                } else {\n                    this.page.menuCurIndex = index;\n                }\n\n                this.page.tinyPage = 0;\n                    getTinyArtOnePageByType(this.artTypes[this.page.menuCurIndex], this.page.tinyPage, this.page.tinyPageSize)\n                    .then((response) => {\n                        this.tinyArticles = response.data;\n                    });\n                window.scrollTo(0,0);\n            },\n\n            /**\n             * 刷新热点新闻\n             */\n            refreshHot: function () {\n                if (this.page.hotPage > 3) {\n                    this.page.hotPage = 0;\n                } else {\n                    this.page.hotPage += 1;\n                }\n                getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                    .then((response) => {\n                        this.hotArticles = response.data;\n                    })\n                    .catch(() => {\n                        this.$message.info(\"抱歉, 发生了点故障\");\n                    });\n            },\n\n            getMoreTinyArt: function () {\n                let artHeight = document.getElementsByTagName('article')[0].offsetHeight;\n                let innerHeight = window.innerHeight;\n                let otherHeight = 70 + 15;\n                let scrollHeight = artHeight - innerHeight + otherHeight;\n                if (scrollHeight <= (document.documentElement.scrollTop + 5)) {\n                    this.page.tinyPage += 1;\n                    getTinyArtOnePageByType(this.artTypes[this.page.menuCurIndex], this.page.tinyPage, this.page.tinyPageSize)\n                        .then((response) => {\n                            for (let i = 0; i < response.data.length; i++) {\n                                this.tinyArticles.push(response.data[i]);\n                            }\n                        })\n                }\n            },\n\n            /**\n             * 跳转至文章页面\n             * @param artId\n             */\n            jumpToArticle: function (artId) {\n                // this.$router.push('/article/' + artId)\n                jumpInNewPage('/article/' + artId);\n            },\n\n            /**\n             * 跳转至作者用户页面\n             * @param cusId\n             */\n            jumpToCustomer: function (cusId) {\n                // this.$router.push('/self/' + cusId);\n                jumpInNewPage('/self/' + cusId);\n            }\n        },\n        data: function () {\n            return {\n                // 记录页面控制信息\n                page: {\n                    menuCurIndex: 0,\n                    menuMajorLen: 8,\n                    menuTip: '更多',\n                    tinyPage: 0,\n                    tinyPageSize: 10,\n                    hotTitle: '热点新闻',\n                    hotPage: 0,\n                    hotPageSize: 6\n                },\n                artTypes: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20'],\n                tinyArticles: [\n                    {   artId: 1, artTitle: \"即将开启降温模式\",\n                        artAbstract:\"降温降雨天气预报预计今晚到明天我州东北部地区阴天普遍有小雨，高山有雨夹雪和大雾，日平均气温下降4～6℃；州西南部晴转多云，局地间有阴天和零星小雨，气温下降2～4℃。请注意相关防御措施。未来24小时内，各县最低气温1℃～10℃，最高气温10～22℃。\",\n                        artTime:\"2019-11-25T08:35:55.000+0000\",\n                        artImage:\"http://p1.pstatp.com/large/pgc-image/Reyxsbp6He2NU3\",\n                        customer: {\n                            cusName:\"光明网\",\n                        }\n                    },\n                    {   artId: 2, artTitle: \"即将开启升温模式\",\n                        artAbstract:\"降温降雨天气预报预计今晚到明天我州东北部地区阴天普遍有小雨，高山有雨夹雪和大雾，日平均气温下降4～6℃；州西南部晴转多云，局地间有阴天和零星小雨，气温下降2～4℃。请注意相关防御措施。未来24小时内，各县最低气温1℃～10℃，最高气温10～22℃。\",\n                        artTime:\"2019-11-25T08:35:55.000+0000\",\n                        artImage:\"\",\n                        customer: {\n                            cusName:\"光明网\",\n                        }\n                    },\n                ],\n                hotArticles: [\n                    { artId: '1', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '2', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '3', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '4', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '5', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '6', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                ],\n                customer: {\n\n                }\n            }\n        }\n    }\n</script>\n\n\n<style scoped src=\"../assets/css/Normal.css\"></style>\n<style scoped>\n    /*.bottom-tip {*/\n    /*    color: #888888;*/\n    /*}*/\n    .edit-entrance {\n        margin-bottom: 10px;\n    }\n</style>"
  },
  {
    "path": "front/src/views/PortView.vue",
    "content": "<template>\n    <div>\n        <login-part v-if=\"page.loginShow\" class=\"login-part\" v-on:changePanel=\"changePanel\"></login-part>\n        <register-part v-if=\"!page.loginShow\" class=\"register-part\" v-on:changePanel=\"changePanel\"></register-part>\n    </div>\n</template>\n\n<script>\n    import LoginPart from '../components/port/LoginPart'\n    import RegisterPart from '../components/port/RegisterPart'\n\n    export default {\n        name: \"PortView.vue\",\n        components: {RegisterPart, LoginPart},\n        methods: {\n            changePanel: function () {\n                if (this.page.loginShow) {\n                    this.page.loginShow = false;\n                } else {\n                    this.page.loginShow = true;\n                }\n            }\n        },\n        data: function () {\n            return {\n                page: {\n                    loginShow: true\n                }\n            }\n        }\n    }\n</script>\n\n<style scoped src=\"../assets/css/Normal.css\"></style>\n<style scoped>\n    .login-part, .register-part {\n        width: 450px;\n        margin: 0 auto;\n        padding-top: 200px;\n    }\n\n\n</style>"
  },
  {
    "path": "front/src/views/SearchView.vue",
    "content": "<template>\n    <div>\n        <header><top-bar class=\"top-bar\" :customer=\"customer\"></top-bar></header>\n        <main>\n            <article>\n                <tiny-article v-for=\"(tinyArticle, i) in tinyArticles\" :key=\"i\" :tinyArticle=\"tinyArticle\"\n                              v-on:jump=\"jumpToArticle\" v-on:editor=\"jumpToCustomer\"></tiny-article>\n            </article>\n            <aside>\n                <!--<right-menu></right-menu>-->\n                <edit-entrance class=\"edit-entrance\"></edit-entrance>\n                <hot-article :title=\"page.hotTitle\" :hot-articles=\"hotArticles\"\n                             v-on:refresh=\"refreshHot\" v-on:jump=\"jumpToArticle\"></hot-article>\n            </aside>\n        </main>\n    </div>\n</template>\n\n<script>\n    import TopBar from \"../components/search/TopBar\";\n    // import TinyCenter from \"../components/search/TinyCenter\";\n    import EditEntrance from \"../components/common/EditEntrance\";\n    import HotArticle from \"../components/common/HotArticle\";\n    import TinyArticle from \"../components/common/TinyArticle\";\n    // import RightMenu from \"../components/index/RightMenu\";\n\n    import Logo from '../assets/image/Logo.png'\n    import {getHotArtOnePage} from \"../control/Load\";\n    import {searchContentSimple} from \"../control/Search\";\n    import {getCusBasicInfo} from \"../control/Self\";\n    import {jumpInCurPage, jumpInNewPage} from \"../util/PageJump\";\n\n\n    export default {\n        name: \"SearchView\",\n        components: {TinyArticle, HotArticle, EditEntrance, TopBar},\n        mounted: function () {\n            window.addEventListener('scroll', this.getMoreTinyArt, false);\n            let key = this.$route.params.key;\n            searchContentSimple(key, this.page.tinyPage, this.page.tinyPageSize)\n                .then((response) => {\n                   this.tinyArticles = response.data;\n                });\n            getCusBasicInfo(0)\n                .then((response) => {\n                    if (response.data) {\n                        this.customer = response.data;\n                    } else {\n                        jumpInCurPage('/port');\n                    }\n\n                });\n            getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                .then((response) => {\n                    this.hotArticles = response.data;\n                });\n            window.scrollTo(0, 0);\n        },\n        methods: {\n            getMoreTinyArt: function () {\n                let artHeight = document.getElementsByTagName('article')[0].offsetHeight;\n                let innerHeight = window.innerHeight;\n                let otherHeight = 70 + 15;\n                let scrollHeight = artHeight - innerHeight + otherHeight;\n                if (scrollHeight <= (document.documentElement.scrollTop + 5)) {\n                    this.page.tinyPage += 1;\n                    // let key = this.$route.params.key;\n                    searchContentSimple(this.page.key, this.page.tinyPage, this.page.tinyPageSize)\n                        .then((response) => {\n                            for (let i = 0; i < response.data.length; i++) {\n                                this.tinyArticles.push(response.data[i]);\n                            }\n                        })\n                }\n            },\n\n            refreshHot: function () {\n                if (this.page.hotPage > 3) {\n                    this.page.hotPage = 0;\n                } else {\n                    this.page.hotPage += 1;\n                }\n                getHotArtOnePage(this.page.hotPage, this.page.hotPageSize)\n                    .then((response) => {\n                        this.hotArticles = response.data;\n                    })\n                    .catch(() => {\n                        this.$message.info(\"抱歉, 发生了点故障\");\n                    });\n            },\n            /**\n             * 跳转至文章页面\n             * @param artId\n             */\n            jumpToArticle: function (artId) {\n                // this.$router.push('/article/' + artId)\n                jumpInNewPage('/article/' + artId);\n            },\n\n            /**\n             * 跳转至作者用户页面\n             * @param cusId\n             */\n            jumpToCustomer: function (cusId) {\n                // this.$router.push('/self/' + cusId);\n                jumpInNewPage('/self/' + cusId);\n            }\n        },\n        data: function () {\n            return {\n                page: {\n                    // menuCurIndex: 0,\n                    // menuMajorLen: 8,\n                    // menuTip: '更多',\n                    tinyPage: 0,\n                    tinyPageSize: 10,\n                    hotTitle: '热点新闻',\n                    hotPage: 0,\n                    hotPageSize: 6,\n                    key: this.$route.params.key\n                },\n                tinyArticles: [\n\n                ],\n                hotArticles: [\n                    { artId: '1', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '2', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '3', artTitle: 'This is the template title of news', artImageUrl: ''},\n                    { artId: '4', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '5', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                    { artId: '6', artTitle: 'This is the template title of news', artImageUrl: Logo},\n                ],\n                customer: {\n\n                },\n\n            }\n        }\n    }\n</script>\n\n<style scoped src=\"../assets/css/Narrow.css\"></style>\n<style scoped>\n    .edit-entrance {\n        margin-bottom: 10px;\n    }\n\n</style>"
  },
  {
    "path": "front/src/views/SelfView.vue",
    "content": "<template>\n    <div>\n        <header><top-bar class=\"top-bar\" :customer=\"customer\"></top-bar></header>\n\n        <main>\n            <!-- section 1 包含 用户的个人信息-->\n            <section>\n                <show-panel :customer=\"ownerCustomer\" :visitor=\"customer\" :is-follow=\"control.isFollow\"></show-panel>\n            </section>\n            <!-- section 2 包含 左右两个部分, 左侧是用户自己的文章, 右侧是用户成就-->\n            <section class=\"clear-float section-main\">\n                <article class=\"self-view-article\">\n                    <tiny-center :ownerCustomer=\"ownerCustomer\" :customerDynamics=\"customerDynamics\"></tiny-center>\n                </article>\n                <aside :style=\"asideStyle\" class=\"self-view-aside\">\n                    <right-menu :info=\"cusCountInfo\"></right-menu>\n                </aside>\n            </section>\n        </main>\n    </div>\n</template>\n\n<script>\n    import TopBar from \"../components/self/TopBar\";\n    import ShowPanel from \"../components/self/EditorMain\";\n    import TinyCenter from \"../components/self/TinyCenter\"\n    import RightMenu from \"../components/self/RightMenu\";\n    import {checkCusFollow, getCusBasicInfo, getCusFeatureInfo, getCusSelfDynamic} from \"../control/Self\";\n    import {jumpInCurPage} from \"../util/PageJump\";\n    export default {\n        name: \"SelfView\",\n        components: {RightMenu, TinyCenter, ShowPanel, TopBar},\n        mounted: function() {\n            window.addEventListener('scroll', this.scrollHandler, false);\n            let cusId = this.$route.params.cusId;\n            getCusBasicInfo(0)\n                .then((response) => {\n                    if (response.data) {\n                        this.customer = response.data;\n                    } else {\n                        jumpInCurPage('/port');\n                    }\n                });\n            getCusBasicInfo(cusId)\n                .then((response) => {\n                    this.ownerCustomer = response.data;\n                })\n                .then(() => {\n                checkCusFollow(this.ownerCustomer.cusId)\n                    .then((response) => {\n                        this.control.isFollow = response.data;\n                    })\n            });\n            getCusFeatureInfo(cusId)\n                .then((response) => {\n                    this.cusCountInfo = response.data;\n                });\n            getCusSelfDynamic(cusId, 0, 10)\n                .then((response) => {\n                    this.customerDynamics = response.data;\n                });\n\n\n        },\n        methods: {\n            scrollHandler: function () {\n                // 侧面栏目悬停\n                let scrollDis = document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset || 0;\n                if (scrollDis > 192) {\n                    this.asideStyle = 'margin-top: 0px';\n                } else {\n                    this.asideStyle = 'position: static;';\n                }\n                // 滚动加载\n                let artHeight = document.getElementsByTagName('article')[0].offsetHeight;\n                let innerHeight = window.innerHeight;\n                let otherHeight = 70 + 182 + 10;\n                let scrollHeight = artHeight - innerHeight + otherHeight;\n                if (scrollHeight <= (document.documentElement.scrollTop + 5)) {\n                    this.control.dnyPage += 1;\n                    getCusSelfDynamic(this.cusId, this.control.dnyPage, this.control.dnyPageSize)\n                        .then((response) => {\n                            // this.customerDynamics = response.data;\n                            for (let i = 0; i < response.data.length; i++) {\n                                this.customerDynamics.push(response.data[i]);\n                            }\n                        });\n                }\n            }\n        },\n        data: function () {\n            return {\n                asideStyle: 'position: static',\n                control: {\n                    dnyPage: 0,\n                    dnyPageSize: 10,\n                    isFollow: false\n                },\n                cusId: this.$route.params.cusId,\n                customer: {\n\n                },\n                ownerCustomer: {\n\n                },\n                cusCountInfo: {\n\n                },\n                customerDynamics: {\n\n                }\n            }\n        }\n    }\n</script>\n\n<style scoped src=\"../assets/css/Narrow.css\"></style>\n<style scoped>\n    .section-main {\n        margin-top: 10px;\n    }\n\n    .self-view-article {\n        float: left;\n    }\n    \n    .self-view-aside {\n\n    }\n</style>"
  },
  {
    "path": "front/vue.config.js",
    "content": "module.exports = {\n    devServer: {\n        // Paths\n        // assetsSubDirectory: 'static',\n        // assetsPublicPath: '/',\n        proxy: {\n            '/api': {\n                target: 'http://0.0.0.0:8080',\n                changeOrigin: true,\n                pathRewrite: {\n                    '^/api': ''   //重写接口\n                }\n            }\n        },\n\n        // // Various Dev Server settings\n        host: '0.0.0.0', // can be overwritten by process.env.HOST\n        port: 8071, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined\n        // autoOpenBrowser: false,\n        // errorOverlay: true,\n        // notifyOnErrors: true,\n        // poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-\n        //\n        //\n        // /**\n        //  * Source Maps\n        //  */\n        //\n        // // https://webpack.js.org/configuration/devtool/#development\n        // devtool: 'cheap-module-eval-source-map',\n        //\n        // // If you have problems debugging vue-files in devtools,\n        // // set this to false - it *may* help\n        // // https://vue-loader.vuejs.org/en/options.html#cachebusting\n        // cacheBusting: true,\n        //\n        // cssSourceMap: true\n    },\n}"
  },
  {
    "path": "spider/Main.py",
    "content": "import model.ArticleModel as ArtMod\nimport model.ReplyModel as RepMod\nimport model.CommentModel as ComMod\nimport model.CustomerModel as CusMod\n\nimport dao.ArticleDao as ArtDao\nimport dao.ReplyDao as RepDao\nimport dao.CommentDao as ComDao\nimport dao.CustomerDao as CusDao\n\nimport process.ArticleProcess as ArtPro\nimport process.ReplyProcess as RepPro\nimport process.CommentProcess as ComPro\nimport process.CustomerProcess as CusPro\n\nimport util.MySql as MySql\nimport util.Json as Json\nimport util.Time as Time\nimport os.path\nimport logging\nimport random\n\nlog_file_name = os.path.join('log', '%s.txt' % Time.Time.get_local_time())\nlogger = logging.getLogger()\nlogger.setLevel(logging.INFO)\nformatter = logging.Formatter('%(levelname)s - %(module)s - %(funcName)s :  \\t%(message)s')\nhandler = logging.FileHandler(filename=log_file_name, mode='a', encoding='utf-8')\nhandler.setFormatter(formatter)\nlogger.addHandler(handler)\n\n\nclass Major:\n\n    def __init__(self, path):\n        db = Json.Json.read_json_file(path)\n        self.__base = MySql.MySql(db_name=db['name'], user=db['user'], password=db['pass'],\n                                  host=db['host'], charset=db['charset'])\n\n        self.__art_pro = ArtPro.ArticleProcess()\n        self.__rep_pro = RepPro.ReplyProcess()\n        self.__com_pro = ComPro.CommentProcess()\n        self.__cus_pro = CusPro.CustomerProcess()\n\n        self.__cus_dao = CusDao.CustomerDao(self.__base)\n        self.__art_dao = ArtDao.ArticleDao(self.__base)\n        self.__com_dao = ComDao.CommentDao(self.__base)\n        self.__rep_dao = RepDao.ReplyDao(self.__base)\n\n    def major(self):\n        categories = ['news_society', 'news_entertainment', 'news_tech', 'news_military', 'news_sports', 'news_car',\n                      'news_finance', 'news_world', 'news_fashion', 'news_travel', 'news_discovery', 'news_baby',\n                      'news_regimen', 'news_story', 'news_essay', 'news_game', 'news_history', 'news_food']\n        # categories = ['news_society']\n\n        for category in categories:\n            print(\"当前类别: %s\" % category)\n            logging.info(\"当前类别: %s\" % category)\n\n            \"\"\" 处理 art \n            \"\"\"\n            try:\n                arts_brief_json = self.__art_pro.get_arts_brief_json_by_category(category)\n                logging.info('%s arts_brief_json 获取 成功' % category)\n            except:\n                print('%s arts_brief_json 获取 失败' % category)\n                logging.exception('%s arts_brief_json 获取 失败' % category)\n                continue\n\n            for art_i, art_brief_json in enumerate(arts_brief_json):\n                print(\"当前新闻: %d/%d %s\" % (art_i, len(arts_brief_json), category))\n                logging.info(\"当前新闻: %d/%d %s\" % (art_i, len(arts_brief_json), category))\n                \"\"\" 新闻作者\n                \"\"\"\n                art_cus_mod = CusMod.CustomerModel()\n                try:\n                    self.__cus_pro.set_art_cus(art_brief_json, art_cus_mod)\n                    self.__cus_dao.insert_then_get_cus(art_cus_mod)\n                    self.__cus_dao.update_cus_feature(category, art_cus_mod.cus_id, flag=True)\n                    logging.info(\"%s-%d art_cus 处理 成功\" % (category, art_i))\n                except:\n                    print(\"%s-%d art_cus 处理 失败\" % (category, art_i))\n                    logging.exception(\"%s-%d art_cus 处理 失败\" % (category, art_i))\n                    continue\n\n                \"\"\" 新闻\n                \"\"\"\n                art_mod = ArtMod.ArticleModel()\n                try:\n                    self.__art_pro.set_art(art_brief_json, category, art_cus_mod.cus_id, art_mod)\n                    if not self.__art_dao.is_art_exist(art_mod.art_spider):\n                        # 新闻不存在的情况\n                        self.__art_dao.insert_art(art_mod)\n                    else:\n                        print(\"art 已存在\")\n                        continue\n                    art_mod.art_id = self.__art_dao.search_art_id_by_spider(art_mod.art_spider)\n                    # art_mod.art_time = self.__art_dao.search_art_time_by_spider(art_mod.art_spider)\n                    logging.info(\"%s-%d art 操作 成功\" % (category, art_i))\n                except:\n                    print(\"%s-%d art 操作 失败\" % (category, art_i))\n                    logging.exception(\"%s-%d art 操作 失败\" % (category, art_i))\n                    continue\n\n                \"\"\" 新闻 用户 行为\n                \"\"\"\n                try:\n                    if self.__art_dao.check_art_cus_relationship(art_mod.art_id, art_cus_mod.cus_id):\n                        self.__cus_dao.insert_cus_behavior(\n                            art_cus_mod.cus_id, art_cus_mod.cus_id, 1, art_mod.art_id, 1,\n                            art_mod.art_id, cbr_time=art_mod.art_time\n                        )\n                        self.__cus_dao.insert_cus_behavior(\n                            art_cus_mod.cus_id, art_cus_mod.cus_id, 2, art_mod.art_id, 1,\n                            art_mod.art_id\n                        )\n                        self.__cus_dao.update_cus_feature(category, art_cus_mod.cus_id)\n                        self.__art_dao.update_art_feature(1, art_mod.art_id, art_mod.art_time)\n                    else:\n                        pass\n                    logging.info(\"%s-%d rt-cus 行为 1 数据库操作 成功\" % (category, art_i))\n                except:\n                    print(\"%s-%d rt-cus 行为 1 数据库操作 失败\" % (category, art_i))\n                    logging.exception(\"%s-%d rt-cus 行为 1 数据库操作 失败\" % (category, art_i))\n                    continue\n\n                \"\"\" 评论与回复处理\n                \"\"\"\n                try:\n                    coms_json = self.__com_pro.get_coms_json(art_brief_json)\n                    if coms_json is None:\n                        continue\n                    logging.info(\"%s-%d coms_json 获取 成功\" % (category, art_i))\n                except:\n                    print(\"\\t%s-%d coms_json 获取 失败\" % (category, art_i))\n                    logging.exception(\"%s-%d coms_json 获取 失败\" % (category, art_i))\n                    continue\n\n                for com_i, com_json in enumerate(coms_json):\n                    print(\"\\t当前评论: %d/%d\" % (com_i, len(coms_json)))\n                    logging.info(\"当前评论: %d/%d\" % (com_i, len(coms_json)))\n                    \"\"\" 评论用户\n                    \"\"\"\n                    com_cus_mod = CusMod.CustomerModel()\n                    try:\n                        self.__cus_pro.set_com_cus(com_json, com_cus_mod)\n                        self.__cus_dao.insert_then_get_cus(com_cus_mod)\n                        self.__cus_dao.update_cus_feature(category, com_cus_mod.cus_id, flag=True)\n                        # self.__cus_dao.cus_watch_other_same_category_art(com_cus_mod.cus_id, art_mod.art_id, category)\n                        logging.info(\"%s-%d-%d com_cus 处理 错误\" % (category, art_i, com_i))\n                    except:\n                        print(\"\\t%s-%d-%d com_cus 处理 错误\" % (category, art_i, com_i))\n                        logging.exception(\"%s-%d-%d com_cus 处理 错误\" % (category, art_i, com_i))\n                        continue\n\n                    \"\"\" 评论\n                    \"\"\"\n                    com_mod = ComMod.CommentModel()\n                    try:\n                        self.__com_pro.set_com(com_json, art_mod.art_id, com_cus_mod.cus_id, com_mod)\n                        if not self.__com_dao.is_com_exist(com_mod.com_spider):\n                            # 如果评论不存在\n                            self.__com_dao.insert_com(com_mod)\n                        else:\n                            print(\"com 已存在\")\n                            continue\n                        com_mod.com_id = self.__com_dao.search_com_id_by_spider(com_mod.com_spider)\n                        logging.info(\"%s-%d-%d com 处理 失败\" % (category, art_i, com_i))\n                    except:\n                        print(\"\\t%s-%d-%d com 处理 失败\" % (category, art_i, com_i))\n                        logging.exception(\"%s-%d-%d com 处理 失败\" % (category, art_i, com_i))\n                        continue\n\n                    \"\"\" 评论 用户 行为\n                    \"\"\"\n                    try:\n                        if self.__com_dao.check_com_cus_relationship(art_mod.art_id, com_mod.com_id, com_cus_mod.cus_id):\n                            self.__cus_dao.insert_cus_behavior(\n                                com_cus_mod.cus_id, art_cus_mod.cus_id, 5, art_mod.art_id, 2,\n                                com_mod.com_id, cbr_time=com_mod.com_time\n                            )\n                            self.__cus_dao.insert_cus_behavior(\n                                com_cus_mod.cus_id, art_cus_mod.cus_id, 2, art_mod.art_id, 1,\n                                art_mod.art_id\n                            )\n                            self.__cus_dao.update_cus_feature(category, com_cus_mod.cus_id)\n                            self.__art_dao.update_art_feature(4, art_mod.art_id, art_mod.art_time)\n                        else:\n                            pass\n                        logging.info(\"%s-%d-%d art-cus 行为 4 数据库操作 成功\" % (category, art_i, com_i))\n                    except:\n                        print(\"\\t%s-%d-%d art-cus 行为 4 数据库操作 失败\" % (category, art_i, com_i))\n                        logging.exception(\"%s-%d-%d art-cus 行为 4 数据库操作 失败\" % (category, art_i, com_i))\n                        continue\n\n                    \"\"\" 评论用户 模拟浏览\n                    \"\"\"\n                    try:\n                        result_list = None\n                        rand_category_num = random.randint(1, 2)\n                        rand_cates = random.sample(categories, rand_category_num)\n                        for rand_cate in rand_cates:\n                            result_list = self.__art_dao.get_same_category_art(art_mod.art_id, rand_cate)\n                            if result_list is not None:\n                                for back_art in result_list:\n                                    try:\n                                        self.__cus_dao.insert_cus_behavior(\n                                            com_cus_mod.cus_id, back_art[1], 2, back_art[0], 1, back_art[0]\n                                        )\n                                        self.__cus_dao.update_cus_feature(rand_cate, com_cus_mod.cus_id, update_num=1)\n                                        self.__art_dao.update_art_feature(6, back_art[0], art_mod.art_time)\n                                    except:\n                                        continue\n                                print(\"\\t%d 用户模拟浏览操作 数量 %d 完成\" % (com_cus_mod.cus_id, len(result_list)))\n                                logging.info(\"%d 模拟浏览操作 数量 %d 完成\" % (com_cus_mod.cus_id, len(result_list)))\n                    except:\n                        print(\"\\t%d 用户模拟浏览操作 失败\" % com_cus_mod.cus_id)\n                        logging.exception(\"%d 用户模拟浏览操作 失败\" % com_cus_mod.cus_id)\n\n                    \"\"\" 回复处理\n                    \"\"\"\n                    try:\n                        reps_json = self.__rep_pro.get_reps_json(com_json)\n                        if reps_json is None:\n                            continue\n                        logging.info(\"%s-%d-%d reps_json 获取 成功\" % (category, art_i, com_i))\n                    except:\n                        print(\"\\t\\t%s-%d-%d reps_json 获取 失败\" % (category, art_i, com_i))\n                        logging.exception(\"%s-%d-%d reps_json 获取 失败\" % (category, art_i, com_i))\n                        continue\n\n                    for rep_i, rep_json in enumerate(reps_json):\n                        \"\"\" 回复用户\n                        \"\"\"\n                        rep_cus_mod = CusMod.CustomerModel()\n                        try:\n                            self.__cus_pro.set_rep_cus(rep_json, rep_cus_mod)\n                            self.__cus_dao.insert_then_get_cus(rep_cus_mod)\n                            self.__cus_dao.update_cus_feature(category, rep_cus_mod.cus_id, flag=True)\n                            logging.info(\"%s-%d-%d-%d rep_cus 处理 成功\" % (category, art_i, com_i, rep_i))\n                        except:\n                            print(\"\\t\\t%s-%d-%d-%d rep_cus 处理 失败\" % (category, art_i, com_i, rep_i))\n                            logging.exception(\"%s-%d-%d-%d rep_cus 处理 失败\" % (category, art_i, com_i, rep_i))\n                            continue\n\n                        \"\"\" 回复\n                        \"\"\"\n                        rep_mod = RepMod.ReplyModel()\n                        try:\n                            self.__rep_pro.set_rep(rep_json, art_mod.art_id,\n                                                   com_mod.com_id, rep_cus_mod.cus_id, rep_mod)\n                            if not self.__rep_dao.is_rep_exist(rep_mod.rep_spider):\n                                self.__rep_dao.search_rep_rep_by_spyder(rep_json, rep_mod)\n                                self.__rep_dao.insert_rep(rep_mod)\n                            else:\n                                print(\"rep 已存在\")\n                                continue\n                            rep_mod.rep_id = self.__rep_dao.search_rep_id_by_spider(rep_mod.rep_spider)\n                            logging.info(\"%s-%d-%d-%d rep 处理 成功\" % (category, art_i, com_i, rep_i))\n                        except:\n                            print(\"\\t\\t%s-%d-%d-%d rep 处理 失败\" % (category, art_i, com_i, rep_i))\n                            logging.exception(\"%s-%d-%d-%d rep 处理 失败\" % (category, art_i, com_i, rep_i))\n                            continue\n\n                        \"\"\" 回复 用户 行为\n                        \"\"\"\n                        try:\n                            if self.__rep_dao.check_rep_cus_relationship(art_mod.art_id, rep_mod.rep_id,\n                                                                         rep_cus_mod.cus_id):\n                                self.__cus_dao.insert_cus_behavior(\n                                    rep_cus_mod.cus_id, art_cus_mod.cus_id, 8, art_mod.art_id, 3,\n                                    rep_mod.rep_id, cbr_time=rep_mod.rep_time\n                                )\n                                self.__cus_dao.insert_cus_behavior(\n                                    rep_cus_mod.cus_id, art_cus_mod.cus_id, 2, art_mod.art_id, 1,\n                                    art_mod.art_id\n                                )\n                                self.__cus_dao.update_cus_feature(category, rep_cus_mod.cus_id)\n                                self.__art_dao.update_art_feature(5, art_mod.art_id, art_mod.art_time)\n                            else:\n                                pass\n                            logging.info(\"%s-%d-%d-%d art-cus 行为 5 数据库操作 成功\" % (category, art_i, com_i, rep_i))\n                        except:\n                            print(\"\\t\\t%s-%d-%d-%d art-cus 行为 5 数据库操作 失败\" % (category, art_i, com_i, rep_i))\n                            logging.exception(\"%s-%d-%d-%d art-cus 行为 5 数据库操作 失败\" % (category, art_i, com_i, rep_i))\n                            continue\n\n                        \"\"\" 回复用户 模拟浏览\n                        \"\"\"\n                        try:\n                            result_list = None\n                            rand_category_num = random.randint(1, 2)\n                            rand_cates = random.sample(categories, rand_category_num)\n                            for rand_cate in rand_cates:\n                                result_list = self.__art_dao.get_same_category_art(art_mod.art_id, rand_cate)\n                                if result_list is not None:\n                                    for back_art in result_list:\n                                        try:\n                                            self.__cus_dao.insert_cus_behavior(\n                                                rep_cus_mod.cus_id, back_art[1], 2, back_art[0], 1, back_art[0]\n                                            )\n                                            self.__cus_dao.update_cus_feature(rand_cate, rep_cus_mod.cus_id, update_num=1)\n                                            self.__art_dao.update_art_feature(6, back_art[0], art_mod.art_time)\n                                        except:\n                                            continue\n                                    print(\"\\t\\t%d 用户模拟浏览操作 数量 %d 完成\" % (rep_cus_mod.cus_id, len(result_list)))\n                                    logging.info(\"%d 用户模拟浏览操作 数量 %d 完成\" % (rep_cus_mod.cus_id, len(result_list)))\n                        except:\n                            print(\"\\t\\t%d 用户模拟浏览操作 失败\" % rep_cus_mod.cus_id)\n                            logging.exception(\"%d 用户模拟浏览操作 失败\" % rep_cus_mod.cus_id)\n\n\nif __name__ == '__main__':\n    Major(os.path.join('properties', 'database.json')).major()\n\n"
  },
  {
    "path": "spider/dao/ArticleDao.py",
    "content": "import util.MySql as MySql\nimport model.ArticleModel as ArtMod\nimport random\n\nimport logging\n\n\nclass ArticleDao:\n    \"\"\" 负责文章的数据库操作\n\n    # 20-04-17 针对新的 SQL 完成修改.\n\n    \"\"\"\n\n\n    def __init__(self, base: MySql.MySql):\n        self.__base = base\n\n\n    def is_art_exist(self, art_spider):\n        \"\"\" 检查新闻是否存在\n\n        # 20-04-17 修改完成\n\n        :param art_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Article where art_spider = '%s'\" % art_spider\n\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                logging.info(\"新闻 art_spider=%s 数据库查询 不存在\" % art_spider)\n                return False\n            else:\n                logging.info(\"新闻 art_spider=%s 数据库查询 已存在\" % art_spider)\n                return True\n        except:\n            logging.exception(\"新闻 art_spider=%s 数据库查询 失败\" % art_spider)\n            raise\n\n\n    def insert_art(self, art_mod: ArtMod.ArticleModel):\n        \"\"\" 插入新闻数据\n\n        # 20-04-17 修改完成\n        # 20-04-23 Rollback BUG Fix\n\n        :param art_mod:\n        :return:\n        \"\"\"\n        try:\n            insert_sql = \"insert into Article(art_title, art_spider, art_type, art_image_url, \" \\\n                         \"art_content, art_tags, \" \\\n                         \"art_cus_id, art_time, art_legal)\" \\\n                         \" values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)\" \\\n                         % (art_mod.art_title, art_mod.art_spider, art_mod.art_type, art_mod.art_image_url,\n                            art_mod.art_content, art_mod.art_tags,\n                            art_mod.art_cus_id, art_mod.art_time, art_mod.art_legal)\n\n            self.__base.execute_sql(insert_sql)\n            self.__base.commit_transactions()\n            logging.info(\"新闻 art_spider=%s 数据库插入 成功\" % art_mod.art_spider)\n        except:\n            # self.__base.commit_rollback()\n            logging.exception(\"新闻 art_spider=%s 数据库插入 失败\" % art_mod.art_spider)\n            raise\n\n\n    def search_art_id_by_spider(self, art_spider):\n        \"\"\" 通过 spider 查询文章 id\n\n        # 20-04-17 修改完成\n\n        :param art_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select art_id from Article where art_spider = '%s'\" % art_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            logging.info(\"新闻 art_spider=%s 数据库查询: art_id 值: %s\" % (art_spider, result[0]))\n            return result[0]\n        except:\n            logging.info(\"新闻 art_spider=%s 数据库查询 art_id 失败\" % art_spider)\n            raise\n\n\n    def search_art_time_by_spider(self, art_spider):\n        \"\"\" 通过 spider 搜索文章时间\n\n        # 20-04-17 修改完毕\n\n        :param art_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select art_time from Article where art_spider = '%s'\" % art_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            logging.info(\"新闻 art_spider=%s art_time 数据库查询: art_id 值: %s\" % (art_spider, result[0]))\n            return result[0]\n        except:\n            logging.info(\"新闻 art_spider=%s art_time 数据库查询 art_id 失败\" % art_spider)\n            raise\n\n\n    def check_art_cus_relationship(self, art_id, cus_id):\n        \"\"\" 检查 art 与 cus 是否存在.\n\n        # 20-04-17 修改完成\n\n        :param art_id:\n        :param cus_id:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Article where art_id=%d and art_cus_id=%d\" % (art_id, cus_id)\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                logging.info(\"关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 不存在\" % (art_id, cus_id))\n                return False\n            else:\n                logging.info(\"关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 存在\" % (art_id, cus_id))\n                return True\n        except:\n            logging.exception(\"关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 错误\" % (art_id, cus_id))\n            raise\n\n\n    @DeprecationWarning\n    def update_art_com_number(self, art_id):\n        try:\n            update_sql = \"update Articles set art_comment_num = art_comment_num + 1 where art_id = %d\" % art_id\n\n            self.__base.execute_sql(update_sql)\n            self.__base.commit_transactions()\n            logging.info(\"update_art_com_number art=%s 评论数 数据库更新 成功\" % art_id)\n        except:\n            # self.__base.commit_rollback()\n            logging.info(\"update_art_com_number art=%s 评论数 数据库更新 失败\" % art_id)\n            raise\n\n\n    def update_art_feature(self, behavior, art_id, art_time):\n        \"\"\" 更新新闻的统计信息\n\n        behavior 为 1 是一个比较特殊的情况, 它将设置 update_art_feature 表中的时间.\n\n        # 20-04-17 修改完成\n        # 20-04-23 Rollback BUG Fix\n        # 20-05-15 修改方法逻辑, 当行为为 6 时, 只将新闻阅读数量加 1\n\n        :param behavior: 这个行为和那个用户行为是两个东西.\n        :param art_id:\n        :param art_time:\n        :return:\n        \"\"\"\n        try:\n            behavior_dict = {\n                1: 'afc_art_time',\n                2: 'afc_like_num',\n                3: 'afc_dislike_num',\n                4: 'afc_com_num',\n                5: 'afc_rep_num',\n                6: 'afc_read_num'\n            }\n\n            if behavior == 1:\n                update_sql = \"insert into ArtFeatureCount(afc_art_id, afc_art_time) values(%d, '%s')\" % (art_id, art_time)\n            elif behavior != 1 or behavior != 6:\n                update_sql = \"update ArtFeatureCount set {0}={1}+1, afc_read_num=afc_read_num+1, afc_art_time=afc_art_time\" \\\n                             \" where afc_art_id=%d\"\\\n                                .format(behavior_dict[behavior], behavior_dict[behavior]) % (art_id)\n            else:\n                update_sql = \"update ArtFeatureCount set afc_read_num=afc_read_num+1, afc_art_time=afc_art_time\" \\\n                             \" where afc_art_id=%d\"\\\n                                % (art_id)\n\n            self.__base.execute_sql(update_sql)\n            # logging.info(\"新闻 art_id=%s 特征 %s 数据库插入 成功\" % (art_id, behavior))\n        except:\n            # self.__base.commit_rollback()\n            # logging.exception(\"新闻 art_id=%s 特征 %s 数据库插入 失败\" % (art_id, behavior))\n            raise\n\n\n    def get_same_category_art(self, cur_art_id, category):\n        \"\"\" 随机选择一定数量的同类文章\n\n        此方法的作用主要是为了帮组增加用户的行为数据.\n        用户随机浏览发生在两个方面: 一是浏览数量的随机 [1, 40], 二是同类别下浏览文章的随机.\n\n        20-05-15 创建方法\n        20-05-19 Bug 修改, 随机逻辑添加\n\n        :param cur_art_id:  当前文章 id\n        :param category:    新闻类别\n        :return:\n        \"\"\"\n        try:\n            rand_num = random.randint(1, 40)\n            select_sql = \"select art_id, art_cus_id from Article \" \\\n                         \"where art_type = '%s' and art_id != %d and timestampdiff(HOUR, art_time, now()) < 240 \" \\\n                         \"order by rand() limit %d\" % \\\n                         (category, cur_art_id, rand_num)\n            self.__base.execute_sql(select_sql)\n            return self.__base.get_result_all()\n        except:\n            raise\n\n"
  },
  {
    "path": "spider/dao/CommentDao.py",
    "content": "import util.MySql as MySql\nimport model.CommentModel as ComMod\n\nimport logging\n\n\nclass CommentDao:\n    \"\"\" 负责评论的数据库操作\n\n    # 20-04-17 针对新的 SQL 完成修改.\n\n    \"\"\"\n\n\n    def __init__(self, base: MySql.MySql):\n        self.__base = base\n\n\n    def is_com_exist(self, com_spider):\n        \"\"\" 检查评论是否存在于数据库\n\n        # 20-04-17 修改完成\n\n        :param com_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Comment where com_spider = '%s'\" % com_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"is_com_exist 评论 com_spider=%s 数据库查询 不存在\" % com_spider)\n                return False\n            else:\n                # logging.info(\"is_com_exist 评论 com_spider=%s 数据库查询 已存在\" % com_spider)\n                return True\n        except:\n            # logging.exception(\"is_com_exist 评论 com_spider=%s 数据库查询 失败\" % com_spider)\n            raise\n\n\n    def insert_com(self, com_mod: ComMod.CommentModel):\n        \"\"\" 将评论插入到数据库中\n\n        # 20-04-17 修改完成\n        # 20-04-23 Rollback BUG Fix\n\n        :param com_mod:\n        :return:\n        \"\"\"\n        try:\n            insert_sql = \"insert into Comment(com_content, com_cus_id,\" \\\n                         \" com_art_id, com_time, com_spider, com_legal)\" \\\n                         \" values ('%s', %d, %d, '%s', '%s', %d)\" \\\n                         % (com_mod.com_content, com_mod.com_cus_id,\n                            com_mod.com_art_id,com_mod.com_time, com_mod.com_spider, com_mod.com_legal)\n            self.__base.execute_sql(insert_sql)\n            self.__base.commit_transactions()\n            # logging.info(\"insert_com 评论 com_spider=%s 数据库插入 成功\" % com_mod.com_spider)\n        except:\n            # self.__base.commit_rollback()\n            # logging.exception(\"insert_com 评论 com_spider=%s 数据库插入 失败\" % com_mod.com_spider)\n            raise\n\n\n    def search_com_id_by_spider(self, com_spider):\n        \"\"\" 利用 spider 查询用户 id\n\n        # 20-04-17 修改完成\n\n        :param com_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select com_id from Comment where com_spider = '%s'\" % com_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            # logging.info(\"search_com_id_by_spider 评论 com_spider=%s 数据库查询: com_id 值: %s\" % (com_spider, result[0]))\n            return result[0]\n        except:\n            # logging.info(\"search_com_id_by_spider 评论 com_spider=%s 数据库查询: com_id 失败\" % com_spider)\n            raise\n\n\n    def check_com_cus_relationship(self, art_id, com_id, cus_id):\n        \"\"\" 检查 com cus 是否存在在数据库中\n\n        # 20-04-17 修改完成\n\n        :param art_id:\n        :param com_id:\n        :param cus_id:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Comment \" \\\n                         \"where com_art_id=%d and com_id=%d and com_cus_id=%d\" % (art_id, com_id, cus_id)\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"评论关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 不存在\" % (art_id, cus_id))\n                return False\n            else:\n                # logging.info(\"评论关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 存在\" % (art_id, cus_id))\n                return True\n        except:\n            # logging.exception(\"评论关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 错误\" % (art_id, cus_id))\n            raise\n"
  },
  {
    "path": "spider/dao/CustomerDao.py",
    "content": "import util.MySql as MySql\nimport model.CustomerModel as CusMod\n\nimport logging\n\n\nclass CustomerDao:\n    \"\"\" 负责用户的数据库操作\n\n    # 20-04-17 针对新的 SQL 完成修改.\n\n    \"\"\"\n\n\n    def __init__(self, base: MySql.MySql):\n        self.__base = base\n\n\n    def is_cus_name_exist(self, cus_name):\n        \"\"\" 检查用户名是否已经存在在数据库中\n\n        # 20-04-17 创建方法\n\n        :param cus_name:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Customer where cus_name = '%s'\" % cus_name\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                logging.info(\"用户 cus_name=%s 数据库查询 不存在\" % cus_name)\n                return False\n            else:\n                logging.info(\"用户 cus_name=%s 数据库查询 已存在\" % cus_name)\n                return True\n        except:\n            logging.exception(\"用户 cus_name=%s 数据库查询 失败\" % cus_name)\n            raise\n\n\n    def get_cus_by_name(self, cus_mod: CusMod.CustomerModel):\n        \"\"\" 通过用户名, 获取用户的信息\n\n        20-04-17 创建方法\n\n        :param cus_mod: 保证 cus_name 被填充\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select cus_id, cus_name, cus_pass, cus_spider, cus_avatar_url, cus_style, cus_legal\" \\\n                         \" from Customer where cus_name = '%s'\" % cus_mod.cus_name\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_all()\n\n            cus_mod.cus_id = result[0][0]\n            # cus_mod.cus_name = result[1]\n            cus_mod.cus_pass = result[0][2]\n            cus_mod.cus_spider = result[0][3]\n            cus_mod.cus_avatar_url = result[0][4]\n            cus_mod.cus_style = result[0][5]\n            cus_mod.cus_legal = result[0][6]\n            logging.info(\"用户 cus_name=%s 数据库查询 完成\" % cus_mod.cus_name)\n        except:\n            logging.exception(\"用户 cus_name=%s 数据库查询 失败\" % cus_mod.cus_name)\n            raise\n\n\n    def insert_then_get_cus(self, cus_mod: CusMod.CustomerModel):\n        \"\"\" 检查用户是否存在, 确认是否插入用户, 获取用户 ID.\n\n        # 20-04-17 创建方法\n\n        :param cus_mod:\n        :return:\n        \"\"\"\n        try:\n            # 如果用户不存在, 就直接插入\n            if not self.is_cus_name_exist(cus_mod.cus_name):\n                self.insert_cus(cus_mod)\n            # 直接从数据库中更新数据.\n            self.get_cus_by_name(cus_mod)\n            logging.info(\"数据库处理成功\")\n        except:\n            logging.exception(\"数据库处理失败\")\n            raise\n\n\n    def insert_cus(self, cus_mod: CusMod.CustomerModel):\n        \"\"\" 向数据库中插入用户数据\n\n        # 20-04-17 检查 OK\n        # 20-04-23 Rollback BUG Fix\n\n        :param cus_mod:\n        :return:\n        \"\"\"\n        try:\n            insert_sql = \"insert into Customer(cus_name, cus_pass, cus_spider, cus_avatar_url, \" \\\n                         \"cus_style, cus_legal)\" \\\n                         \" values ('%s', '%s', '%s', '%s', '%s', %d)\" \\\n                         % (cus_mod.cus_name, cus_mod.cus_pass, cus_mod.cus_spider, cus_mod.cus_avatar_url,\n                            cus_mod.cus_style, cus_mod.cus_legal)\n            self.__base.execute_sql(insert_sql)\n            self.__base.commit_transactions()\n            logging.info(\"用户 cus_spider=%s 数据库插入 成功\" % cus_mod.cus_spider)\n        except:\n            # self.__base.commit_rollback()\n            logging.exception(\"用户 cus_spider=%s 数据库插入 失败\" % cus_mod.cus_spider)\n            raise\n\n\n    def insert_cus_behavior(self, cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_art_id, cbr_type, cbr_target_id, cbr_time=None):\n        \"\"\" 插入用户行为\n\n        # 20-04-17 修改完成\n        # 20-04-19 方法修改, 将第二个 insert 移除, 同时允许行为时间为空\n        # 20-04-23 Rollback BUG Fix\n\n        :param cbr_cus_id_from:\n        :param cbr_cus_id_to:\n        :param cbr_behavior:\n        :param cbr_time:\n        :param cbr_art_id:\n        :param cbr_type:\n        :param cbr_target_id:\n        :return:\n        \"\"\"\n        try:\n            if cbr_time is not None:\n                insert_sql = \"insert into CusBehaviorRecord(cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_time, cbr_art_id, cbr_type, cbr_target_id) \" \\\n                             \"values (%d, %d, %d, '%s', %d, %d, %d)\" \\\n                              % (cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_time, cbr_art_id, cbr_type, cbr_target_id)\n            else:\n                insert_sql = \"insert into CusBehaviorRecord(cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_art_id, cbr_type, cbr_target_id) \" \\\n                             \"values (%d, %d, %d, %d, %d, %d)\" \\\n                              % (cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_art_id, cbr_type, cbr_target_id)\n            # insert_sql1 = \"insert into CusBehaviorRecord(cbr_cus_id_from, cbr_cus_id_to, cbr_behavior, cbr_time, cbr_art_id, cbr_type, cbr_target_id) \" \\\n            #              \"values (%d, %d, 2, '%s', %d, %d, %d)\" \\\n            #               % (cbr_cus_id_from, cbr_cus_id_to, cbr_time, cbr_art_id, cbr_type, cbr_target_id)\n\n            self.__base.execute_sql(insert_sql)\n            # self.__base.execute_sql(insert_sql1)\n            self.__base.commit_transactions()\n            logging.info(\"用户 cus_id=%s 与用户 cus_id=%s 行为 %s 数据库插入 成功\" % (cbr_cus_id_from, cbr_cus_id_to, cbr_behavior))\n        except:\n            # self.__base.commit_rollback()\n            logging.exception(\"用户 cus_id=%s 与用户 cus_id=%s 行为 %s 数据库插入 失败\" % (cbr_cus_id_from, cbr_cus_id_to, cbr_behavior))\n            raise\n\n\n    def update_cus_feature(self, category, cus_id, update_num=2, flag=False):\n        \"\"\" 更新用户统计数据\n\n        这将是一个非常操蛋的方法.\n\n        # 20-04-17 修改完成\n        # 20-04-18 BUG 修改: 每调用一次此方法, 用户特征的增加应该与文章特征的增加保持一致, 即增加 2, 而非 1.\n        # 20-04-23 接口修改, 添加 flag 字段\n        # 20-04-23 Rollback BUG Fix\n        # 20-05-15 修改方法, 允许设置特征更新数量\n\n        :param category:\n        :param cus_id:\n        :param update_num:  每调用一次此方法, 需要用户特征的增加应该与文章特征的增加保持一致, 有些时候是 1, 有些时候是 2, 默认为 2\n        :param flag:\n                            当 flag 为 True 且 cus_id 指向的用户已存在时, category 参数将失效,\n                            用于插入一个仅有 cfc_cus_id 的记录, 即初始化.\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from CusFeatureCount where cfc_cus_id=%d\" % cus_id\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"特征 用户 cus_id=%s 数据库查询 不存在\" % (cus_id))\n                if flag:\n                    # 发现用户不存在, 只是想单纯地创建用户\n                    update_sql = \"insert into CusFeatureCount(cfc_cus_id) value (%d)\" % cus_id\n                else:\n                    # 发现用户不存在, 在创建用户的基础上, 还想更新一些数据.\n                    update_sql = \"insert into CusFeatureCount(cfc_cus_id, {0}) values(%d, %d)\" \\\n                                     .format('cfc_' + category) % (cus_id, update_num)\n            else:\n                # logging.info(\"特征 用户 cus_id=%s 数据库查询 存在\" % (cus_id))\n                update_sql = \"update CusFeatureCount set {0}={1}+{2} where cfc_cus_id=%d\" \\\n                                 .format('cfc_' + category, 'cfc_' + category, update_num) % cus_id\n\n            self.__base.execute_sql(update_sql)\n            # logging.info(\"用户 cus_id=%s 类别 %s 特征 数据库插入 成功\" % (cus_id, category))\n        except:\n            # self.__base.commit_rollback()\n            # logging.exception(\"用户 cus_id=%s 类别 %s 特征 数据库插入 失败\" % (cus_id, category))\n            raise\n\n\n    @DeprecationWarning\n    def is_cus_exist(self, cus_spider):\n        \"\"\" 检查用户是否存在与数据库\n\n        :param cus_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Customer where cus_spider = '%s'\" % cus_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"用户 cus_spider=%s 数据库查询 不存在\" % cus_spider)\n                return False\n            else:\n                # logging.info(\"用户 cus_spider=%s 数据库查询 已存在\" % cus_spider)\n                return True\n        except:\n            # logging.exception(\"用户 cus_spider=%s 数据库查询 失败\" % cus_spider)\n            raise\n\n\n    @DeprecationWarning\n    def search_cus_id_by_spider(self, cus_spider):\n        \"\"\" 利用 spider 查询用户 id\n\n        :param cus_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select cus_id from Customer where cus_spider = '%s'\" % cus_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            # logging.info(\"用户 cus_spider=%s 数据库查询: cus_id 值: %s\" % (cus_spider, result[0]))\n            return result[0]\n        except:\n            # logging.info(\"用户 cus_spider=%s 数据库查询 cus_id 失败\" % cus_spider)\n            raise\n\n\n"
  },
  {
    "path": "spider/dao/ReplyDao.py",
    "content": "import util.MySql as MySql\nimport model.ReplyModel as RepMod\n\nimport logging\n\n\nclass ReplyDao:\n    \"\"\" 回复消息数据库处理\n\n    # 20-04-17 依据新的 SQL 修改\n\n    \"\"\"\n\n\n    def __init__(self, base: MySql.MySql):\n        self.__base = base\n\n\n    def is_rep_exist(self, rep_spider):\n        \"\"\" 通过 spider 判断回复是否存在在数据库中\n\n        # 20-04-17 修改完成\n\n        :param rep_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Reply where rep_spider = '%s'\" % rep_spider\n\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"is_rep_exist 回复 rep_spider=%s 数据库查询 不存在\" % rep_spider)\n                return False\n            else:\n                # logging.info(\"is_rep_exist 回复 rep_spider=%s 数据库查询 已存在\" % rep_spider)\n                return True\n        except:\n            # logging.exception(\"is_rep_exist 回复 rep_spider=%s 数据库查询 失败\" % rep_spider)\n            raise\n\n\n    def insert_rep(self, rep_mod: RepMod.ReplyModel):\n        \"\"\" 插入回复数据\n\n        # 20-04-17 修改完成\n        # 20-04-23 Rollback BUG Fix\n\n        :param rep_mod:\n        :return:\n        \"\"\"\n        try:\n            if rep_mod.rep_rep_id is None:\n                insert_sql = \"insert into Reply(rep_content, rep_type, rep_time,\" \\\n                             \" rep_cus_id, rep_art_id, rep_com_id, \" \\\n                             \" rep_spider, rep_legal)\" \\\n                             \" values ('%s', %d, '%s', %d, %d, %d, '%s', %d)\" \\\n                             % (str(rep_mod.rep_content), int(rep_mod.rep_type), str(rep_mod.rep_time),\n                                int(rep_mod.rep_cus_id), int(rep_mod.rep_art_id), int(rep_mod.rep_com_id),\n                                str(rep_mod.rep_spider), int(rep_mod.rep_legal))\n            else:\n                insert_sql = \"insert into Reply(rep_content, rep_type, rep_time,\" \\\n                             \" rep_cus_id, rep_art_id, rep_com_id, \" \\\n                             \"rep_rep_id, rep_spider, rep_legal)\" \\\n                             \" values ('%s', %d, '%s', %d, %d, %d, %d, '%s', %d)\" \\\n                             % (str(rep_mod.rep_content), int(rep_mod.rep_type), str(rep_mod.rep_time),\n                                int(rep_mod.rep_cus_id), int(rep_mod.rep_art_id), int(rep_mod.rep_com_id),\n                                int(rep_mod.rep_rep_id), str(rep_mod.rep_spider), int(rep_mod.rep_legal))\n\n            self.__base.execute_sql(insert_sql)\n            self.__base.commit_transactions()\n            # logging.info(\"回复 rep_spider=%s 数据库插入 成功\" % rep_mod.rep_spider)\n        except:\n            # self.__base.commit_rollback()\n            # logging.exception(\"回复 rep_spider=%s 数据库插入 失败\" % rep_mod.rep_spider)\n            raise\n\n\n    def search_rep_id_by_spider(self, rep_spider):\n        \"\"\" 通过 spider 获取回复的 id\n\n        # 20-04-17 修改完成\n\n        :param rep_spider:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select rep_id from Reply where rep_spider = '%s'\" % rep_spider\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            # logging.info(\"新闻 rep_spider=%s 数据库查询: rep_id 值: %s\" % (rep_spider, result[0]))\n            return result[0]\n        except:\n            # logging.info(\"新闻 rep_spider=%s 数据库查询 rep_id 失败\" % rep_spider)\n            raise\n\n\n    def check_rep_cus_relationship(self, art_id, rep_id, cus_id):\n        \"\"\" 检查回复与用户是否存在在数据库中\n\n        # 20-04-17 修改完成\n\n        :param art_id:\n        :param rep_id:\n        :param cus_id:\n        :return:\n        \"\"\"\n        try:\n            search_sql = \"select count(*) from Reply \" \\\n                         \"where rep_art_id=%d and rep_id=%d and rep_cus_id=%d\" % (art_id, rep_id, cus_id)\n            self.__base.execute_sql(search_sql)\n            result = self.__base.get_result_one()\n            if result[0] == 0:\n                # logging.info(\"回复关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 不存在\" % (art_id, cus_id))\n                return False\n            else:\n                # logging.info(\"回复关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 存在\" % (art_id, cus_id))\n                return True\n        except:\n            # logging.exception(\"回复关系 新闻 art_id=%s 用户 cus_id=%s 数据库查询 错误\" % (art_id, cus_id))\n            raise\n\n\n    def search_rep_rep_by_spyder(self, rep_json, rep_mod: RepMod.ReplyModel):\n        \"\"\" 处理回复的回复\n\n        # 20-04-17 修改完成\n\n        :param rep_json:\n        :param rep_mod:\n        :return:\n        \"\"\"\n        try:\n            rep_rep_spider = str(rep_json['reply_to_comment']['id'])\n            rep_mod.rep_rep_id = self.search_rep_id_by_spider(rep_rep_spider)\n            rep_mod.rep_type = 1\n            # logging.info(\"rep_rep_id 与 rep_type 数据库查询 成功\")\n        except:\n            rep_mod.rep_rep_id = None\n            rep_mod.rep_type = 0\n            # logging.warning(\"rep_rep_id 与 rep_type 数据库查询 失败\")\n"
  },
  {
    "path": "spider/dao/__init__.py",
    "content": ""
  },
  {
    "path": "spider/model/ArticleModel.py",
    "content": "class ArticleModel:\n\n    def __init__(self):\n        self.art_id = None\n        self.art_title = None\n        self.art_content = None\n\n        self.art_spider = None\n        self.art_type = None\n        self.art_tags = None\n\n        self.art_image_url = None\n        self.art_time = None\n        self.art_cus_id = None\n\n        self.art_legal = 1\n\n\n\n"
  },
  {
    "path": "spider/model/CommentModel.py",
    "content": "class CommentModel:\n\n    def __init__(self):\n        self.com_id = None\n        self.com_content = None\n        self.com_time = None\n        self.com_cus_id = None\n        self.com_art_id = None\n\n        self.com_spider = None\n        self.com_legal = 1\n\n"
  },
  {
    "path": "spider/model/CustomerModel.py",
    "content": "class CustomerModel:\n    def __init__(self):\n        \"\"\"\n        cus_gender 默认 0\n        cus_time 默认插入时间\n\n        20-04-17 修改\n        \"\"\"\n        self.cus_id = None\n        self.cus_name = None\n        self.cus_pass = None\n        self.cus_spider = None\n        self.cus_avatar_url = None\n        self.cus_style = None\n        self.cus_legal = 1\n\n\n"
  },
  {
    "path": "spider/model/ReplyModel.py",
    "content": "class ReplyModel:\n\n    def __init__(self):\n        self.rep_id = None\n        self.rep_content = None\n        self.rep_type = None\n\n        self.rep_time = None\n        self.rep_spider = None\n\n        self.rep_cus_id = None\n        self.rep_art_id = None\n        self.rep_com_id = None\n        self.rep_rep_id = None\n\n        self.rep_legal = 1\n"
  },
  {
    "path": "spider/model/__init__.py",
    "content": ""
  },
  {
    "path": "spider/process/ArticleProcess.py",
    "content": "import util.Request as Request\nimport util.Time as Time\nimport util.Driver as Driver\nimport model.ArticleModel as ArtMod\nimport model.CustomerModel as CusMod\n\nimport logging\n\n\nclass ArticleProcess:\n    \"\"\" 文章数据的获取与填充填充\n\n    # 20-17-04 依据新的 SQL 修改\n\n    \"\"\"\n\n\n    def get_arts_brief_json_by_category(self, category):\n        \"\"\" 获取文章缩率信息, 不包括文章内容\n\n        # 20-04-17 方法检查 OK\n\n        参考接口:\n            http://m.toutiao.com/list/?tag=__all__&ac=wap&count=20&format=json_raw&as=A17538D54D106FF&cp=585DF0A65F0F1E1&min_behot_time=1482491618\n\n        :param category:\n            '社会': 'news_society',\n            '娱乐': 'news_entertainment',\n            '科技': 'news_tech',\n            '军事': 'news_military',\n            '体育': 'news_sports'\n            '汽车': 'news_car',\n            '财经': 'news_finance',\n            '国际': 'news_world',\n            '时尚': 'news_fashion',\n            '旅游': 'news_travel',\n            '探索': 'news_discovery',\n            '育儿': 'news_baby',\n            '养生': 'news_regimen',\n            '故事': 'news_story',\n            '美文': 'news_essay',\n            '游戏': 'news_game',\n            '历史': 'news_history',\n            '美食': 'news_food',\n        :return:\n            example:\n            [\n                Object{...},\n                Object{...},\n                Object{...},\n                {\n                    \"media_name\":\"呦呦科学馆\",\n                    \"ban_comment\":0,\n                    \"abstract\":\"大家对屎壳郎都会有所耳闻，屎壳郎的原名是蜣螂（qiāng láng），一种痴迷于推粪球的昆虫，我们一直以来都没有什么正面评价，有时候在评价一个人不好的时候，会把他说成是屎壳郎。虽然屎壳郎在我们这儿，没有什么正面的评价，但是有些地方把它当成是神哦！不是负面的神，而是太阳神！\",\n                    \"image_list\":[\n                        {\n                            \"url\":\"http://p6-tt.byteimg.com/img/pgc-image/a9b944c7417847e687b5f97aeb2798ad~tplv-tt-cs0:640:360.jpg\",\n                            \"width\":640,\n                            \"height\":360\n                        },\n                        {\n                            \"url\":\"http://p6-tt.byteimg.com/img/pgc-image/2ca2e18621f942daa6b7e602205b4492~tplv-tt-cs0:525:576.jpg\",\n                            \"width\":525,\n                            \"height\":295\n                        },\n                        {\n                            \"url\":\"http://p9-tt.byteimg.com/img/pgc-image/3605e63e394e45b494d2cc5914662a8c~tplv-tt-cs0:628:344.jpg\",\n                            \"width\":628,\n                            \"height\":344\n                        }\n                    ],\n                    \"datetime\":\"2020-01-03 20:30\",\n                    \"article_type\":0,\n                    \"more_mode\":true,\n                    \"tag\":\"news_story\",\n                    \"has_m3u8_video\":0,\n                    \"display_dt\":1577527020,\n                    \"has_mp4_video\":0,\n                    \"aggr_type\":1,\n                    \"cell_type\":0,\n                    \"article_sub_type\":0,\n                    \"bury_count\":0,\n                    \"title\":\"屎壳郎的故事\",\n                    \"source_icon_style\":1,\n                    \"tip\":0,\n                    \"has_video\":false,\n                    \"share_url\":\"http://toutiao.com/a6775056296904229390/?app=news_article&is_hit_share_recommend=0\",\n                    \"source\":\"呦呦科学馆\",\n                    \"comment_count\":0,\n                    \"article_url\":\"http://toutiao.com/group/6775056296904229390/\",\n                    \"publish_time\":1577527020,\n                    \"group_flags\":0,\n                    \"gallary_image_count\":4,\n                    \"action_extra\":\"{\"channel_id\": 3189398979}\",\n                    \"tag_id\":\"6775056296904229390\",\n                    \"source_url\":\"/i6775056296904229390/\",\n                    \"display_url\":\"http://toutiao.com/group/6775056296904229390/\",\n                    \"is_stick\":false,\n                    \"item_id\":\"6775056296904229390\",\n                    \"repin_count\":12,\n                    \"cell_flag\":262155,\n                    \"source_open_url\":\"sslocal://profile?uid=566976876133454\",\n                    \"level\":0,\n                    \"digg_count\":6,\n                    \"behot_time\":1578054637,\n                    \"hot\":0,\n                    \"cursor\":1578054637999,\n                    \"url\":\"http://toutiao.com/group/6775056296904229390/\",\n                    \"user_repin\":0,\n                    \"has_image\":true,\n                    \"video_style\":0,\n                    \"media_info\":{\n                        \"avatar_url\":\"http://p1.pstatp.com/large/ffe800001f90d3b65398\",\n                        \"media_id\":1629031487078411,\n                        \"name\":\"呦呦科学馆\",\n                        \"user_verified\":true\n                    },\n                    \"group_id\":\"6775056296904229390\"\n                },\n                Object{...}\n            ]\n\n        :param category:\n        :return:\n        \"\"\"\n        try:\n            url = 'http://m.toutiao.com/list/?tag={0}&ac=wap&count=20&format=json_raw&as=A17538D54D106FF&cp=585DF0A65F0F1E1&min_behot_time=1482491618'.format(category)\n            headers = {\n                \"Host\": \"m.toutiao.com\",\n                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'\n            }\n            cookies = {\n                \"tt_webid\": \"6754560229981750791\",\n                \"WEATHER_CITY\": \"%E5%8C%97%E4%BA%AC\",\n                \"csrftoken\": \"4e76bad8185f77ea8b647e50e3bb0e26\",\n                \"_ga\": \"GA1.2.268549673.1572668703\",\n                \"__utmz\": \"24953151.1578051975.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)\",\n                \"__utma\": \"24953151.268549673.1572668703.1578051975.1578221568.2\",\n                \"SLARDAR_WEB_ID\": \"60060dd2-e5b2-470c-b7f4-09b8d877a031\",\n                \"ttcid\": \"3f7ad0f028c54aa584367115a3fa7cb028\",\n                \"__ac_nonce\": \"05ecba43c0082bbdfb3e\",\n                \"__ac_signature\": \"O2auwAAgEBACmHx7dlnWxztnr9AAGWz3dGBVQL.r0H1se1MOmPcu.0Mxo.Y9Zem1qLCx5rV13rttFjnqiBP7d4KfTBbgN8Az4ip.Po5Ht9XBlX2CZW8ZIUZV9blZ9smX461\",\n                \"s_v_web_id\": \"verify_kamdklmd_rcCyRT2X_ZLBe_4OQI_Brjy_Q7HFKjeCzPbt\",\n                \"__tasessionId\": \"gx98j8z1x1590404157654\",\n                \"tt_scid\": \"nLlc9z1mWQgXRhJFHC7i29KXmnHM9sZynN1Ue86iBmH5DPSaDONSaQYQz7mqHMcMf924\"\n            }\n\n\n            result = Request.Request(url, headers, cookies).more()['data']\n            # print(result)\n            logging.info(\"获取新闻缩率信息 %s 成功\" % url)\n            return result\n        except:\n            # logging.exception(\"获取新闻缩率信息 失败\")\n            return None\n\n\n    def set_art(self, art_brief_json, category, art_cus_id, art_mod: ArtMod.ArticleModel):\n        \"\"\" 插入新闻内容\n\n        # 20-04-17 修改完成\n\n        :param art_brief_json:\n        :param category:\n        :param art_cus_id:\n        :param art_mod:\n        :return:\n        \"\"\"\n        driver = Driver.Driver.get_chrome_driver()\n\n        try:\n            url = \"https://www.toutiao.com/a{0}/\".format(art_brief_json['item_id'])\n            driver.implicitly_wait(3)\n            driver.get(url)\n\n            art_mod.art_spider = art_brief_json['item_id']\n            try:\n                if len(art_brief_json['image_list']) == 0:\n                    art_mod.art_image_url = ''\n                else:\n                    for tar in art_brief_json['image_list']:\n                        art_mod.art_image_url = tar['url']\n                        break\n            except:\n                art_mod.art_image_url = ''\n            art_mod.art_legal = 1\n            art_mod.art_time = Time.Time.time_trans(art_brief_json['publish_time'])\n            art_mod.art_cus_id = art_cus_id\n            art_mod.art_id = None\n            try:\n                art_mod.art_tags = art_brief_json['keywords']\n            except:\n                art_mod.art_tags = ''\n            art_mod.art_type = category\n            art_mod.art_title = art_brief_json['title']\n\n            art_mod.art_content = driver.find_element_by_class_name(\"syl-page-article\").get_attribute('innerHTML')\n\n            logging.info(\"设置新闻数据 url=%s 成功\" % url)\n        except:\n            # logging.exception(\"设置新闻数据 失败\")\n\n            raise\n        finally:\n            driver.close()\n\n\n    @DeprecationWarning\n    def get_art_json(self, art_brief_json):\n        \"\"\" 获得一则新闻的具体内荣\n\n        参考接口:\n            http://m.toutiao.com/i6364969235889783298/info/\n\n        :param art_brief_json:\n        :return:\n            example:\n            {\n                \"detail_source\":\"正向娱乐energy\",\n                \"media_user\":{\n                    \"screen_name\":\"正向娱乐energy\",\n                    \"no_display_pgc_icon\":false,\n                    \"avatar_url\":\"http://p1.pstatp.com/thumb/ff0600002c7db3631cde\",\n                    \"id\":\"52681187308\",\n                    \"user_auth_info\":{\n                        \"auth_type\":\"0\",\n                        \"other_auth\":{\n                            \"interest\":\"优质娱乐领域创作者\"\n                        },\n                        \"auth_info\":\"青云计划获奖者 优质娱乐领域创作者\"\n                    }\n                },\n                \"publish_time\":1574065021,\n                \"hotwords\":[\n                    {\n                        \"stress_type\":0,\n                        \"hot_word\":\"录明星整容视频勒索\"\n                    },\n                    {\n                        \"stress_type\":1,\n                        \"hot_word\":\"宁静再演孝庄\"\n                    },\n                    ...\n                ],\n                \"labels\":[\n\n                ],\n                \"title\":\"李诞向左，池子向右，脱口秀背后的悲喜人生\",\n                \"url\":\"http://toutiao.com/group/6760557790046978567/\",\n                \"high_quality_flag\":\"0\",\n                \"impression_count\":\"790339\",\n                \"is_original\":true,\n                \"is_pgc_article\":true,\n                \"content\":\"<div class=\"pgc-img\">... ... 剩下的都是文章内容的 HTML 形式\",\n                \"source\":\"正向娱乐energy\",\n                \"comment_count\":326,\n                \"logo_show_strategy\":\"normal\",\n                \"hupu_content_image_urls\":[\n                    \"\"\n                ],\n                \"creator_uid\":52408555030\n            }\n        \"\"\"\n        try:\n            art_url = 'http://m.toutiao.com/i{0}/info/'.format(art_brief_json['item_id'])\n            headers = {\n                \"Host\": \"m.toutiao.com\",\n                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'\n            }\n            result = Request.Request(art_url, headers).more()['data']\n            logging.info(\"获取新闻内容数据 %s 成功\" % art_url)\n            return result\n        except:\n            # logging.exception(\"获取新闻内容数据 失败\")\n            return None\n\n\n\n\n\n\n"
  },
  {
    "path": "spider/process/CommentProcess.py",
    "content": "import util.Request as Request\nimport util.Time as Time\nimport model.CommentModel as ComMod\n\nimport logging\n\n\nclass CommentProcess:\n    \"\"\" 评论数据的获取与填充\n\n    # 20-17-04 依据新的 SQL 修改\n\n    \"\"\"\n\n\n    def get_coms_json(self, art_brief_json):\n        \"\"\" 获取评论列表\n\n        # 20-04-17 代码检查 OK\n        # 20-04-28 将单次获取评论的数量从 10 变成了 20\n        # 20-05-02 日志打印内容修改, 修改 URL 中的 aid 参数, 这个作用不明确, 先调小一点\n\n        参考接口:\n            https://www.toutiao.com/article/v2/tab_comments/?aid=24&app_name=toutiao-web&group_id=6732655510039822860&item_id=6732655510039822860&offset=0&count=5\n\n        :param art_brief_json:\n        :return:\n\n            example:\n            [\n                Object{...},\n                {\n                    \"comment\":{\n                        \"id\":6732812439848665099,\n                        \"id_str\":\"6732812439848665099\",\n                        \"text\":\"见过一个女孩，搞防晒真的是全副武装，... 承认我是个女的😂\",\n                        \"content_rich_span\":\"{\"links\":[]}\",\n                        \"reply_count\":71,\n                        \"reply_list\":[\n\n                        ],\n                        \"digg_count\":1372,\n                        \"bury_count\":0,\n                        \"forward_count\":0,\n                        \"create_time\":1567605056,\n                        \"score\":1.8130338214242776,\n                        \"user_id\":1684053931865459,\n                        \"user_name\":\"用户896765315284\",\n                        \"remark_name\":\"\",\n                        \"user_profile_image_url\":\"http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3793/3131589739~120x256.image\",\n                        \"user_verified\":false,\n                        \"interact_style\":0,\n                        \"is_following\":0,\n                        \"is_followed\":0,\n                        \"is_blocking\":0,\n                        \"is_blocked\":0,\n                        \"is_pgc_author\":0,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"verified_reason\":\"\",\n                        \"user_bury\":0,\n                        \"user_digg\":0,\n                        \"user_relation\":0,\n                        \"user_auth_info\":\"\",\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\",\n                        \"aid\":35,\n                        \"large_image_list\":[\n\n                        ],\n                        \"thumb_image_list\":[\n\n                        ],\n                        \"media_info\":{\n                            \"name\":\"\",\n                            \"avatar_url\":\"\"\n                        },\n                        \"tags\":null,\n                        \"platform\":\"feifei\",\n                        \"has_author_digg\":0,\n                        \"multi_media\":null,\n                        \"has_multi_media\":false,\n                        \"show_tags\":0\n                    },\n                    \"ad\":null,\n                    \"embedded_data\":null,\n                    \"id\":6732812439848665099,\n                    \"cell_type\":1\n                },\n                Object{...},\n                Object{...},\n                Object{...}\n            ],\n\n        \"\"\"\n        try:\n            com_url = 'https://www.toutiao.com/api/pc/article/v4/tab_comments/?' \\\n                          'aid=1&app_name=toutiao-web&group_id={0}&item_id={1}&offset=0&count={2}' \\\n                        .format(art_brief_json['group_id'], art_brief_json['item_id'], 20)\n            headers = {\n                \"Host\": \"www.toutiao.com\",\n                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'\n            }\n            result = Request.Request(com_url, headers).more()['data']\n            logging.info(\"获取评论页数据 %s 成功\" % com_url)\n            return result\n        except:\n            logging.exception(\"获取评论页数据 失败\")\n            return None\n\n\n    def set_com(self, com_json, art_id, cus_id, com_mod: ComMod.CommentModel):\n        \"\"\" set a single comment\n\n        # 20-04-17 修改完成\n\n        :param com_json:\n        :param art_id:\n        :param cus_id:\n        :param com_mod:\n        :return:\n        \"\"\"\n        try:\n            com_mod.com_cus_id = cus_id\n            com_mod.com_time = Time.Time.time_trans(com_json['comment']['create_time'])\n            com_mod.com_content = com_json['comment']['text']\n            com_mod.com_art_id = art_id\n            com_mod.com_id = None\n            com_mod.com_legal = 1\n            com_mod.com_spider = str(com_json['comment']['id'])\n\n            logging.info(\"设置评论数据 成功\")\n        except:\n            logging.exception(\"设置评论数据 失败\")\n            raise\n"
  },
  {
    "path": "spider/process/CustomerProcess.py",
    "content": "import model.CustomerModel as CusMod\nimport util.Md5 as Md5\nimport logging\n\n\nclass CustomerProcess:\n    \"\"\" 用户数据的获取与填充\n\n    # 20-17-04 依据新的 SQL 修改\n\n    \"\"\"\n\n\n    def set_art_cus(self, art_brief_json, cus_mod: CusMod):\n        \"\"\" 设置用户信息\n\n        # 20-04-17 修改完成\n\n        :param art_brief_json:\n        :param cus_mod:\n        :return:\n        \"\"\"\n        try:\n            cus_mod.cus_spider = str(art_brief_json['media_info']['media_id'])\n            cus_mod.cus_legal = 1\n            cus_mod.cus_style = '这个用户很懒啥也没写'\n            cus_mod.cus_avatar_url = art_brief_json['media_info']['avatar_url']\n            # cus_mod.cus_name = art_brief_json['media_info']['name'] + cus_mod.cus_spider[0:4]\n            cus_mod.cus_name = art_brief_json['media_info']['name']\n            cus_mod.cus_pass = Md5.Md5.set_cus_pass(\"123456\")\n            cus_mod.cus_id = None\n            # logging.info(\"设置新闻用户信息 成功\")\n        except:\n            # logging.exception(\"设置新闻用户信息 失败\")\n            raise\n\n\n    def set_com_cus(self, com_json, cus_mod: CusMod.CustomerModel):\n        \"\"\" 设置评论用户\n\n        # 20-04-17 修改完成\n\n        :param com_json:\n        :param cus_mod:\n        :return:\n        \"\"\"\n        try:\n            cus_mod.cus_spider = str(com_json['comment']['user_id'])\n            cus_mod.cus_legal = 1\n            cus_mod.cus_style = '这个用户很懒啥也没写'\n            cus_mod.cus_avatar_url = com_json['comment']['user_profile_image_url']\n            # cus_mod.cus_name = com_json['comment']['user_name'] + cus_mod.cus_spider[0:4]\n            cus_mod.cus_name = com_json['comment']['user_name']\n            cus_mod.cus_pass = Md5.Md5.set_cus_pass(\"123456\")\n            cus_mod.cus_id = None\n            # logging.info(\"设置评论用户信息 成功\")\n        except:\n            # logging.exception(\"设置评论用户信息 失败\")\n            raise\n\n\n    def set_rep_cus(self, rep_json, cus_mod: CusMod.CustomerModel):\n        \"\"\" 设置回复用户\n\n        # 20-04-17 修改完成\n\n        :param rep_json:\n        :param cus_mod:\n        :return:\n        \"\"\"\n        try:\n            cus_mod.cus_spider = str(rep_json['user']['user_id'])\n            cus_mod.cus_legal = 1\n            try:\n                cus_mod.cus_style = rep_json['user']['description']\n                if cus_mod.cus_style == '':\n                    cus_mod.cus_style = '这个用户很懒啥也没写'\n            except:\n                # logging.warning(\"cus_style 获取 失败\")\n                cus_mod.cus_style = '这个用户很懒啥也没写'\n            cus_mod.cus_avatar_url = rep_json['user']['avatar_url']\n            # cus_mod.cus_name = rep_json['user']['name'] + cus_mod.cus_spider[0:4]\n            cus_mod.cus_name = rep_json['user']['name']\n            cus_mod.cus_pass = Md5.Md5.set_cus_pass(\"123456\")\n            cus_mod.cus_id = None\n\n            # logging.info(\"设置回复用户信息 成功\")\n        except:\n            # logging.exception(\"设置回复用户信息 失败\")\n            raise\n\n\n"
  },
  {
    "path": "spider/process/ReplyProcess.py",
    "content": "import util.Request as Request\nimport util.Time as Time\nimport model.ReplyModel as RepMod\n\nimport logging\n\n\nclass ReplyProcess:\n    \"\"\" 回复数据的获取与填充\n\n    # 20-17-04 依据新的 SQL 修改\n\n    \"\"\"\n\n\n    def get_reps_json(self, com_json):\n        \"\"\" 获取 回复 包括 回复的回复 的数据\n\n        # 20-04-17 代码检查 OK\n        # 20-05-07 代码修改, 当获取的内容为 None 时, raise Exception\n\n        数据接口参考:\n            https://www.toutiao.com/2/comment/v2/reply_list/?aid=24&app_name=toutiao-web&id=6733175468666748931&offset=0&count=20&repost=0\n\n        :param com_json:\n        :return:\n            example:\n            [\n                {\n                    \"id\":6777317683702185995,\n                    \"id_str\":\"6777317683702185995\",\n                    \"create_time\":1577967243,\n                    \"text\":\"西瓜整个买的 好像只有中锅和美锅 其他都是切开卖的\",\n                    \"content\":\"西瓜整个买的 好像只有中锅和美锅 其他都是切开卖的\",\n                    \"content_rich_span\":\"{\"links\":[]}\",\n                    \"digg_count\":6,\n                    \"forward_count\":0,\n                    \"user_digg\":false,\n                    \"is_owner\":false,\n                    \"has_author_digg\":0,\n                    \"thumb_image_list\":[\n\n                    ],\n                    \"large_image_list\":[\n\n                    ],\n                    \"user\":{\n                        \"user_id\":4540648983,\n                        \"name\":\"拔吊无情3344\",\n                        \"screen_name\":\"拔吊无情3344\",\n                        \"avatar_url\":\"http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/ec4a0856405d4b3c92febe148fbe26e5~120x256.image\",\n                        \"description\":\"\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_following\":false,\n                        \"is_followed\":false,\n                        \"is_blocking\":false,\n                        \"is_blocked\":false,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"interact_style\":0,\n                        \"is_pgc_author\":false,\n                        \"user_relation\":0,\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\"\n                    },\n                    \"group\":null,\n                    \"repost_params\":null\n                },\n                {\n                    \"id\":6777509244712976384,\n                    \"id_str\":\"6777509244712976384\",\n                    \"create_time\":1578011843,\n                    \"text\":\"现在我也是半个半个买了，太贵了\",\n                    \"content\":\"现在我也是半个半个买了，太贵了\",\n                    \"content_rich_span\":\"{\"links\":[]}\",\n                    \"digg_count\":1,\n                    \"forward_count\":0,\n                    \"user_digg\":false,\n                    \"is_owner\":false,\n                    \"has_author_digg\":0,\n                    \"thumb_image_list\":[\n\n                    ],\n                    \"large_image_list\":[\n\n                    ],\n                    \"user\":{\n                        \"user_id\":5943146542,\n                        \"name\":\"灵辉72330603\",\n                        \"screen_name\":\"灵辉72330603\",\n                        \"avatar_url\":\"http://p3.pstatp.com/thumb/5ac8001ee3bc186542d0\",\n                        \"description\":\"\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_following\":false,\n                        \"is_followed\":false,\n                        \"is_blocking\":false,\n                        \"is_blocked\":false,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"interact_style\":0,\n                        \"is_pgc_author\":false,\n                        \"user_relation\":0,\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\"\n                    },\n                    \"group\":null,\n                    \"repost_params\":null,\n                    \"reply_to_comment\":{\n                        \"id\":6777317683702185995,\n                        \"id_str\":\"6777317683702185995\",\n                        \"text\":\"西瓜整个买的 好像只有中锅和美锅 其他都是切开卖的\",\n                        \"content_rich_span\":\"{\"links\":[]}\",\n                        \"status\":1,\n                        \"user_id\":4540648983,\n                        \"user_name\":\"拔吊无情3344\",\n                        \"user_profile_image_url\":\"http://sf6-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/ec4a0856405d4b3c92febe148fbe26e5~120x256.image\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_pgc_author\":false,\n                        \"is_followed\":false,\n                        \"is_following\":false,\n                        \"user_relation\":0,\n                        \"large_image_list\":[\n\n                        ],\n                        \"thumb_image_list\":[\n\n                        ]\n                    }\n                },\n                {\n                    \"id\":6765863594673405963,\n                    \"id_str\":\"6765863594673405963\",\n                    \"create_time\":1575300379,\n                    \"text\":\"那精致的吃法。或用水果叉还撒盐。\",\n                    \"content\":\"那精致的吃法。或用水果叉还撒盐。\",\n                    \"content_rich_span\":\"{\"links\":[]}\",\n                    \"digg_count\":5,\n                    \"forward_count\":0,\n                    \"user_digg\":false,\n                    \"is_owner\":false,\n                    \"has_author_digg\":0,\n                    \"thumb_image_list\":[\n\n                    ],\n                    \"large_image_list\":[\n\n                    ],\n                    \"user\":{\n                        \"user_id\":64403579548,\n                        \"name\":\"軋軋闹猛\",\n                        \"screen_name\":\"軋軋闹猛\",\n                        \"avatar_url\":\"http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/e581bc04e29a489cb38ce9a6ab689a11~120x256.image\",\n                        \"description\":\"hello\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_following\":false,\n                        \"is_followed\":false,\n                        \"is_blocking\":false,\n                        \"is_blocked\":false,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"interact_style\":0,\n                        \"is_pgc_author\":false,\n                        \"user_relation\":0,\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\"\n                    },\n                    \"group\":null,\n                    \"repost_params\":null\n                },\n                {\n                    \"id\":6778028635040694272,\n                    \"id_str\":\"6778028635040694272\",\n                    \"create_time\":1578132771,\n                    \"text\":\"是太贵了\",\n                    \"content\":\"是太贵了\",\n                    \"content_rich_span\":\"{\"links\":[]}\",\n                    \"digg_count\":0,\n                    \"forward_count\":0,\n                    \"user_digg\":false,\n                    \"is_owner\":false,\n                    \"has_author_digg\":0,\n                    \"thumb_image_list\":[\n\n                    ],\n                    \"large_image_list\":[\n\n                    ],\n                    \"user\":{\n                        \"user_id\":85682550538,\n                        \"name\":\"高木同学w\",\n                        \"screen_name\":\"高木同学w\",\n                        \"avatar_url\":\"http://sf6-ttcdn-tos.pstatp.com/img/user-avatar/8a763365d363bd85011a7c3c9e319bca~120x256.image\",\n                        \"description\":\"\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_following\":false,\n                        \"is_followed\":false,\n                        \"is_blocking\":false,\n                        \"is_blocked\":false,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"interact_style\":0,\n                        \"is_pgc_author\":false,\n                        \"user_relation\":0,\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\"\n                    },\n                    \"group\":null,\n                    \"repost_params\":null,\n                    \"reply_to_comment\":{\n                        \"id\":6765863594673405963,\n                        \"id_str\":\"6765863594673405963\",\n                        \"text\":\"那精致的吃法。或用水果叉还撒盐。\",\n                        \"content_rich_span\":\"{\"links\":[]}\",\n                        \"status\":1,\n                        \"user_id\":64403579548,\n                        \"user_name\":\"軋軋闹猛\",\n                        \"user_profile_image_url\":\"http://sf3-ttcdn-tos.pstatp.com/img/tos-cn-i-0022/e581bc04e29a489cb38ce9a6ab689a11~120x256.image\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_pgc_author\":false,\n                        \"is_followed\":false,\n                        \"is_following\":false,\n                        \"user_relation\":0,\n                        \"large_image_list\":[\n\n                        ],\n                        \"thumb_image_list\":[\n\n                        ]\n                    }\n                },\n                {\n                    \"id\":6777979056702308367,\n                    \"id_str\":\"6777979056702308367\",\n                    \"create_time\":1578121229,\n                    \"text\":\"要是中国一个西瓜二百块钱，那也会用牙签吃。\",\n                    \"content\":\"要是中国一个西瓜二百块钱，那也会用牙签吃。\",\n                    \"content_rich_span\":\"{\"links\":[]}\",\n                    \"digg_count\":0,\n                    \"forward_count\":0,\n                    \"user_digg\":false,\n                    \"is_owner\":false,\n                    \"has_author_digg\":0,\n                    \"thumb_image_list\":[\n\n                    ],\n                    \"large_image_list\":[\n\n                    ],\n                    \"user\":{\n                        \"user_id\":109181261304,\n                        \"name\":\"7853624655665862\",\n                        \"screen_name\":\"7853624655665862\",\n                        \"avatar_url\":\"http://sf1-ttcdn-tos.pstatp.com/img/mosaic-legacy/3797/2889309425~120x256.image\",\n                        \"description\":\"\",\n                        \"user_verified\":false,\n                        \"verified_reason\":\"\",\n                        \"user_auth_info\":\"\",\n                        \"is_following\":false,\n                        \"is_followed\":false,\n                        \"is_blocking\":false,\n                        \"is_blocked\":false,\n                        \"author_badge\":[\n\n                        ],\n                        \"author_badge_night\":[\n\n                        ],\n                        \"interact_style\":0,\n                        \"is_pgc_author\":false,\n                        \"user_relation\":0,\n                        \"user_decoration\":\"\",\n                        \"band_url\":\"\",\n                        \"band_name\":\"\"\n                    },\n                    \"group\":null,\n                    \"repost_params\":null\n                }\n            ]\n\n        \"\"\"\n        try:\n            reply_url = 'https://www.toutiao.com/api/pc/2/comment/v4/reply_list/?' \\\n                        'aid=24&app_name=toutiao-web&id={0}&offset=0&count={1}&repost=0' \\\n                        .format(com_json['id'], 20)\n            headers = {\n                \"Host\": \"www.toutiao.com\",\n                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'\n            }\n            result = Request.Request(reply_url, headers).more()['data']['data']\n            if result is None:\n                raise\n            logging.info(\"获取回复信息 %s 成功\" % reply_url)\n            return result\n        except:\n            # logging.exception(\"获取回复信息 失败\")\n            raise\n\n\n    def set_rep(self, rep_json, rep_art_id, rep_com_id, rep_cus_id, rep_mod: RepMod.ReplyModel):\n        \"\"\" 填充回复数据\n\n        # 20-04-17 修改完成\n\n        :param rep_json:\n        :param rep_art_id:\n        :param rep_com_id:\n        :param rep_cus_id:\n        :param rep_mod:\n        :return:\n        \"\"\"\n        try:\n            rep_mod.rep_rep_id = None\n            rep_mod.rep_legal = 1\n            rep_mod.rep_cus_id = rep_cus_id\n            rep_mod.rep_time = Time.Time.time_trans(rep_json['create_time'])\n            rep_mod.rep_content = rep_json['text']\n            rep_mod.rep_com_id = rep_com_id\n            rep_mod.rep_id = None\n            rep_mod.rep_art_id = rep_art_id\n            rep_mod.rep_spider = str(rep_json['id'])\n\n            # logging.info(\"设置回复信息 成功\")\n        except:\n            # logging.exception(\"获取回复信息 失败\")\n            raise\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "spider/process/__init__.py",
    "content": ""
  },
  {
    "path": "spider/util/Driver.py",
    "content": "import selenium.webdriver as webdriver\nimport selenium.webdriver.chrome.options as options\n\n\nclass Driver:\n\n    def __init__(self):\n        pass\n\n    @staticmethod\n    def get_chrome_driver():\n        \"\"\" 获得模拟浏览器 Chrome\n\n        :return:\n        \"\"\"\n\n        chrome_options = options.Options()\n        chrome_prefs = {}\n        chrome_options.experimental_options[\"prefs\"] = chrome_prefs\n        chrome_prefs[\"profile.default_content_settings\"] = {\"images\": 2}\n        chrome_prefs[\"profile.managed_default_content_settings\"] = {\"images\": 2}\n\n        # chrome_options.add_argument('--headless')\n        return webdriver.Chrome(chrome_options=chrome_options)"
  },
  {
    "path": "spider/util/Json.py",
    "content": "import json\n\n\nclass Json:\n\n    def __init__(self):\n        pass\n\n    @staticmethod\n    def read_json_file(path, encoding='utf-8'):\n        js = open(path, encoding=encoding)\n        return json.load(js)"
  },
  {
    "path": "spider/util/Md5.py",
    "content": "import hashlib\n\n\nclass Md5:\n\n    @staticmethod\n    def set_cus_pass(password):\n        \"\"\" 为用户密码进行 MD-5 加密\n\n        :param password: 密码明文\n        :return:\n        \"\"\"\n        hl = hashlib.md5()\n        hl.update(password.encode('utf-8'))\n        return hl.hexdigest()\n"
  },
  {
    "path": "spider/util/MySql.py",
    "content": "import pymysql\nimport logging\n\n\nclass MySql:\n\n    def __init__(self, db_name, user, password, host=\"localhost\", charset=\"utf8\"):\n        self.__db_handle = pymysql.connect(host=host,\n                                           user=user,\n                                           password=password,\n                                           db=db_name,\n                                           charset=charset)\n        self.__cursor = self.__db_handle.cursor()\n\n    def execute_sql(self, sql):\n        # logging.info(\"%s\" % sql)\n        self.__cursor.execute(sql)\n\n    def commit_transactions(self):\n        # logging.info(\"事务提交\")\n        self.__db_handle.commit()\n\n    def commit_rollback(self):\n        # logging.info(\"提交回滚\")\n        self.__db_handle.rollback()\n\n    def get_result_all(self):\n        result = self.__cursor.fetchall()\n        # logging.info(\"获得数据: %s\" % result)\n        return result\n\n    def get_result_one(self):\n        result = self.__cursor.fetchone()\n        # logging.info(\"获得数据: %s\" % result)\n        return result\n"
  },
  {
    "path": "spider/util/Request.py",
    "content": "import requests\n\n\nclass Request:\n    \"\"\" 用于创建访问请求\n    \"\"\"\n\n    def __init__(self, url, headers=None, cookies=None):\n        self.__url = url\n        self.__headers = headers\n        self.__cookie = cookies\n\n    def set_url(self, url):\n        self.__url = url\n\n    def set_headers(self, headers):\n        self.__headers = headers\n\n    def set_cookie(self, cookie):\n        self.__cookie = cookie\n\n    def more(self):\n        resp = requests.get(self.__url, headers=self.__headers, cookies=self.__cookie)\n        resp.encoding = 'utf8mb4'\n        self.__cookie = resp.cookies\n        return resp.json()\n"
  },
  {
    "path": "spider/util/Time.py",
    "content": "import time\n\n\nclass Time:\n\n    @staticmethod\n    def time_trans(time_data):\n        time_stamp = time_data\n        time_array = time.localtime(time_stamp)\n        return time.strftime(\"%Y-%m-%d %H-%M-%S\", time_array)\n\n    @staticmethod\n    def get_local_time():\n        return Time.time_trans(time.time())\n"
  },
  {
    "path": "spider/util/__init__.py",
    "content": ""
  }
]