如何使用ssm实现中国文学作品网站+vue

336 篇文章 0 订阅
143 篇文章 0 订阅

@TOC

ssm450中国文学作品网站+vue

第1章 绪论

1.1 研究背景

互联网概念的产生到如今的蓬勃发展,用了短短的几十年时间就风靡全球,使得全球各个行业都进行了互联网的改造升级,标志着互联网浪潮的来临。在这个新的时代,各行各业都充分考虑互联网是否能与本行业进行结合,是否能解决本行业或者本行业中某些方面的自古以来的痛点。长期以来,数据内容,数据传播,数据储存等都是一门门专业的内容,因为需要记住的内容很多,造成古人的言简意赅,如今互联网的到来让数据更加的清晰好认不复杂,一目了然不出错,毕竟在整个历史上数据的丢失,传承的断代,都是因为数据不能好好的保存,不能好好的流传。当年的年代用互联网思维和互联网技术,对大量数据的录入更新,存储汇总,备份分析方面,使得远远的超过传统的数据管理技术。在这样的时代潮流下,采用新技术开发新软件,对传统行业进行革命性的改造成为了当今的主流。本次开发中国文学作品网站,解决了书籍信息管理关于数据方面的管理分析,存储传输的痛点,不仅仅对管理员提供了便利,还能提高用户的满意度。

1.2目的和意义

此次中国文学作品网站的开发,需要用到的知识不仅涉及到界面设计与功能设计方面的知识,还需要涉及到数据库与编程语言上面的知识,这些知识点对于一个即将毕业的学生来说,一是为了巩固在校所学相关专业知识;二是为了让学生学会如何将专业理论知识运用于现实软件的开发过程;三是让学生明白知识是无穷无尽的,要时刻明白活到老学到老的真正含义,让学生要养成时刻学习的习惯,同时也要相信通过此次程序的开发,会让学生对于专业知识的理解与软件开发水平的提高有着极大的帮助。

1.3 论文研究内容

论文设计的结构也是依照程序开发的流程进展的,也涉及到功能需求分析,功能设计与实现,程序测试等流程。

绪论:讲解课题的背景与意义,展示论文结构。

程序开发技术:讲解程序运用到的工具与技术知识。

系统分析:讲解程序的功能需求与开发可行性问题。

系统设计:讲解程序的功能与数据库的设计。

系统实现:讲解程序功能与界面实现。

系统测试:讲解程序的功能测试。

第2章 程序开发技术

2.1 Mysql数据库

为了更容易理解Mysql数据库,接下来就对其具备的主要特征进行描述。

(1)首选Mysql数据库也是为了节省开发资金,因为网络上对Mysql的源码都已进行了公开展示,开发者根据程序开发需要可以进行下载,并做一些改动就可以使用在程序中,可以推动开发者开发此程序的开发进度。

(2)SQL数据语言在Mysql里面也同样适用

(3)Mysql不仅可以支持多种编程语言,比如在校期间学到的C语言,Java语言,以及课后接触的PHP语言,C++语言等编程语言,它都能很好的支持,而且Mysql的安装与使用还不挑剔使用平台。

(4)Mysql可以支持具有千万条数据记录的数据库,电脑操作系统在进行首次安装或者是重装时,可以根据需要选择安装32位或64位操作系统,这两种操作系统对表文件的支持力度不一样,32位的操作系统最多可以存放4GB的表文件,64位操作系统最多可以存放8TB的表文件。

(5)Mysql数据库可以通过GPL协议进行个性化定制,需要开发者自己对数据库的源代码进行修改,以此开发出属于自己的Mysql。

2.2 Java语言

程序开发语言有很多,但是截至目前,Java语言在IT领域内,仍然是最被认可,以及被广泛运用的编写语言之一,因此在选择此程序的编写语言上,果断选择这门编程语言进行程序开发。可以说经过了这么多年的发展,Java语言不仅在Web开发领域有了突出性贡献,而且在大数据开发领域以及Android开发领域都得到了广泛运用。由于Java语言拥有较强的扩展性能,并且表现出的稳定性能,让其成为大型后端系统开发语言首选,现如今,Java语言也成为了一种常用的互联网平台的解决方案。

作为一种源码在网络上开源的面向对象的程序开发Java语言,由它开发完成的程序是不可能直接运行在各大平台的,Java程序的运行,需要在操作平台上配置其运行的环境,包括数据库软件与Java程序开发软件等工具的安装与配置。在Win7,Win10或其它操作平台上配置Java程序运行环境,只要环境配置成功,Java程序都可以运行起来。

第3章 系统分析

在进行系统分析之前,需要从网络上或者是图书馆的开发类书籍中收集大量的资料,因为这个环节也是帮助即将开发的程序软件制定一套最优的方案,一旦确定了程序软件需要具备的功能,就意味着接下来的工作和任务都是围绕着这个方案执行的,所以系统分析需要对程序功能反复进行思考和研究。

3.1可行性分析

开发一款系统软件之前,用户都会思考这个软件程序值不值得去开发,把开发软件过程中可能涉及到的问题罗列出来,并一个个分析解决,以此来确定开发这款程序软件是否有必要,这样的分析方法也能帮助用户降低损失,不至于开发者开发进度进行到一半之后,突然遇到问题就放弃对软件的开发,到那时,资金损失,人力投入等方面就损耗太大了。

3.1.1技术可行性分析

此次开发程序使用到的开发工具有:Eclipse,Mysql等工具,使用的开发语言是Java,选择的开发工具和开发语言都是在大学课堂接触并学习过,后期因为自己也比较感兴趣,所以也通过网络渠道,或借助图书馆的开发类书籍进行过软件开发知识的系统学习,让自己有了一定的知识积累,加上自己在校期间也独立开发过一些软件作品,也积累了一定的开发经验,所以这次毕设作品的制作在技术上无须担忧过多。

3.1.2经济可行性分析

目前的信息时代,对信息的管理趋于高效化,便捷化,这也是计算机大力普及所带来的便利,此程序软件在设备选用上,依靠的是比较大众的电脑设备,对电脑的配置没有过多要求,一般学校的计算机机房的电脑都可以满足程序开发需求,另外,开发出此款程序,让信息处理变得高效率,其所带来的高效益是远超程序开发的低成本的,因此程序开发的资金投入是可以忽略不计的。

3.1.3操作可行性分析

程序软件的操作界面是符合大众审美的需求,功能模块的布局也是类似于社会上同种类型的软件,因此使用者操作该软件可以无需培训就上手。加上现在计算机入驻各家各户,大部分人的计算机操作水平都比较高,这样的局面也表明开发出来的程序在操作性问题上也是不用担心的。

综合上面的可行性论证,基本可以确定程序开发完全可行。

3.2系统运行环境

程序经过编码可以实现对程序设计的功能。但是编码实现时需要一定的配置环境,包括了电脑上的硬件环境,也包括在电脑操作系统上安装的软件环境。

硬件环境:一台可以正常使用并能够上网的笔记本或者是电脑,电脑内存最低要求4个G,电脑的中央处理器可以配置i5CPU。

软件环境:运用的微软操作系统是比较稳定的win7旗舰版系统,采用比较熟练360安全浏览器,并在此系统上通过浏览器下载安装好Eclipse软件,下载安装好MYSQL软件等。

3.3系统流程分析

分析程序的流程,涉及到程序的整体操作流程,通过分析与设计,绘制的程序操作流程图见下图。此程序为了确保安全,会让使用者通过登录模块验证信息,符合要求的使用者才有权限操作程序。

图3-1 程序操作流程图

程序处理数据会涉及到数据的录入环节,绘制的添加流程见下图。程序录入数据过程中,始终与数据库保持同步。

图3-2 信息添加流程图

程序里面的数据也会出现错误,因此就有相应的修改数据的功能,绘制的程序修改流程见下图。此过程也是跟后台数据库进行数据同步显示。

图3-3信息修改流程图

程序数据存放于数据仓库,有时也会涉及到数据删除,此过程对应的流程图见下图。数据信息被删除之后,数据库里面也就没有了该数据信息了。

图3-4 信息删除流程图

第4章 系统设计

4.1 系统设计的原则

在系统设计过程中,也需要遵循相应的设计原则,这些设计原则可以帮助设计者在短时间内设计出符合设计规范的设计方案。设计原则主要有可靠性,安全性,可定制化,可扩展性,可维护性,可升级性以及客户体验等原则。下面就对这些原则进行简要阐述。

可靠性:一个软件是否可靠决定了其是否被用户使用,设计不可靠的软件,用户很容易就遗弃;

安全性:程序软件承担了信息的保存与管理等事务,安全性不足的软件会导致使用者承担巨大的损失;所以系统安全也是需要考虑进入的;

可定制化:市场环境从来都不是一直固定不变,面对客户群体的改变,以及使用环境的改变,市场需求的改变等因素,程序软件也要易于调整以适应各种变化;

可扩展性:程序软件在运行使用期间,也需要及时引进当下的新技术来进行系统优化,主要就是在系统功能层面,系统性能层面上进行相应的扩展,只有这样才能让系统在实际生活中继续占有市场;

可维护性:程序软件的维护需要一定量的资金,不管是排除现有程序错误,还是变更软件的现有需求,都需要在软件技术上投入一定资金,所以易于维护的软件程序就可以降低技术层面的资金消耗;

可升级性:程序软件的投入使用,会面临用户数量增多的情况,用户对软件的使用率也会提升,所以系统面临这种情况,仍然需要通过升级保持性能的合理,这样才能够适应市场;

客户体验:设计出来的程序软件在界面上不能够太复杂,要遵循界面设计的原理设计出简单,方便操作的功能操作界面,让用户易于接受软件,并乐于使用软件提供的功能。

4.2 系统结构设计

在系统结构设计上,经综合考虑还是选择比C/S更省资金的B/S结构模式,现如今浏览器已经实现了普及,并在技术上逐渐完善和成熟,它在节约软件开发成本的基础上,还能实现原本用专业软件操作才能实现的强大功能。总之,B/S结构是当下全新的,认可度高的系统构造技术。系统结构设计图通过绘制,效果展示如下:

图4-1 系统结构设计图

4.3功能结构设计

在管理员功能模块确定下来的基础上,对管理员各个功能进行设计,确定管理员功能的详细模块。绘制的管理员功能结构见下图。

[[表注释]]

系个人信息管理

管轮播图管理

管书籍管理

管留言管理

大论坛管理

修个人信息修改

修改密码

新发布帖子

是回复帖子

删删除帖子

删留言删除

留言新增

留言修改

删轮播图删除

新轮播图新增

修轮播图修改

用新增书籍

用修改书籍

用删除书籍

管公告管理

新新增公告

吸修改公告

删删除公告

图4.3 管理员功能结构图

4.4 数据库设计

开发一个系统也需要提前设计数据库。这里的数据库是相关数据的集合,存储在一起的这些数据也是按照一定的组织方式进行的。目前,数据库能够服务于多种应用程序,则是源于它存储方式最佳,具备数据冗余率低的优势。虽然数据库为程序提供信息存储服务,但它与程序之间也可以保持较高的独立性。总而言之,数据库经历了很长一段时间的发展,从最初的不为人知,到现在的人尽皆知,其相关技术也越发成熟,同时也拥有着坚实的理论基础。

4.4.1 数据库概念设计

这部分内容需要借助数据库关系图来完成,也需要使用专门绘制数据库关系图的工具,比如Visio工具就可以设计E-R图(数据库关系图)。设计数据库,也需要按照设计的流程进行,首先还是要根据需求完成实体的确定,分析实体具有的特征,还有对实体间的关联关系进行确定。最后才是使用E-R模型的表示方法,绘制本系统的E-R图。不管是使用亿图软件,还是Visio工具,对于E-R模型的表示符号都一样,通常矩形代表实体,实体间存在的关系用菱形符号表示,实体的属性也就是实体的特征用符号椭圆表示。最后使用直线将矩形,菱形和椭圆等符号连接起来。接下来就开始对本系统的E-R图进行绘制。

(1)下图是论坛实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\论坛.jpg 图4.1 论坛实体属性图

(2)下图是用户实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\用户.jpg 图4.2 用户实体属性图

(3)下图是书籍收藏实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\书籍收藏.jpg 图4.3 书籍收藏实体属性图

(4)下图是作者实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\作者.jpg 图4.4 作者实体属性图

(5)下图是公告信息实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\公告信息.jpg 图4.5 公告信息实体属性图

(6)下图是书籍留言实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\书籍留言.jpg 图4.6 书籍留言实体属性图

(7)下图是章节实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\章节.jpg 图4.7 章节实体属性图

(8)下图是书籍实体和其具备的属性。

C:\Users\Administrator\Desktop\img\wenxuezuopin\书籍.jpg 图4.8 书籍实体属性图

4.4.2 数据库表结构

在进行这部分设计之前,需要明白和掌握数据类型以及各个数据类型的长度范围等知识,因为在一张具体的数据表中,为了方便理解,这里就举个简单的例子。比如用户信息表,这个表格的字段就是用户这个实体具备的属性,这时就需要对字段进行数据类型,以及字段长度的设置,也要设置一个主键来作为用户信息表的唯一标识。这些都是数据库表结构设计需要完成的内容。根据中国文学作品网站的功能设计以及数据库设计要求,展示该系统的数据表结构。

表4.1字典表

序号列名数据类型说明允许空
1IdIntid
2dic_codeString字段
3dic_nameString字段名
4code_indexInteger编码
5index_nameString编码名字
6super_idInteger父字段id
7beizhuString备注
8create_timeDate创建时间

表4.2论坛表

序号列名数据类型说明允许空
1IdIntid
2forum_nameString帖子标题
3yonghu_idInteger用户
4zuozhe_idInteger作者
5users_idInteger老师
6forum_contentString发布内容
7super_idsInteger父id
8forum_typesInteger帖子类型
9forum_state_typesInteger帖子状态
10insert_timeDate发帖时间
11update_timeDate修改时间
12create_timeDate创建时间

表4.3公告信息表

序号列名数据类型说明允许空
1IdIntid
2gonggao_nameString公告名称
3gonggao_photoString公告图片
4gonggao_typesInteger公告类型
5insert_timeDate公告发布时间
6gonggao_contentString公告详情
7create_timeDate创建时间

表4.4书籍表

序号列名数据类型说明允许空
1IdIntid
2zuozhe_idInteger作者
3shuji_nameString书籍名称
4shuji_photoString书籍封面
5shuji_typesInteger书籍类型
6shuji_clicknumInteger点击次数
7shangxia_typesInteger是否上架
8shuji_contentString书籍简介
9insert_timeDate添加时间
10create_timeDate创建时间

表4.5书籍收藏表

序号列名数据类型说明允许空
1IdIntid
2shuji_idInteger书籍
3yonghu_idInteger用户
4shuji_collection_typesInteger类型
5insert_timeDate收藏时间
6create_timeDate创建时间

表4.6书籍留言表

序号列名数据类型说明允许空
1IdIntid
2shuji_idInteger书籍
3yonghu_idInteger用户
4shuji_liuyan_textString留言内容
5reply_textString回复内容
6insert_timeDate留言时间
7update_timeDate回复时间
8create_timeDate创建时间

表4.7用户表

序号列名数据类型说明允许空
1IdIntid
2yonghu_nameString用户姓名
3yonghu_phoneString用户手机号
4yonghu_id_numberString用户身份证号
5yonghu_photoString用户头像
6yonghu_emailString电子邮箱
7create_timeDate创建时间

表4.8章节表

序号列名数据类型说明允许空
1IdIntid
2shuji_idInteger书籍
3zhangjie_nameString章节名称
4zhangjie_contentString章节内容
5paixuInteger排序
6insert_timeDate添加时间
7create_timeDate创建时间

表4.9作者表

序号列名数据类型说明允许空
1IdIntid
2zuozhe_nameString作者姓名
3zuozhe_phoneString作者手机号
4zuozhe_id_numberString作者身份证号
5zuozhe_photoString作者头像
6yonghu_emailString电子邮箱
7create_timeDate创建时间

表4.10管理员表

序号列名数据类型说明允许空
1IdIntid
2roleString角色
3addtimeDate新增时间
  1. 系统实现

系统实现这个章节的内容主要还是展示系统的功能界面设计效果,在实现系统基本功能,比如修改,比如添加,比如删除等管理功能的同时,也显示出系统各个功能的界面实现效果,该部分内容一方面与前面提到的系统分析,系统设计的内容相呼应,另一方面也是一个实际成果的展示。

5.1管理员功能实现

5.1.1 书籍管理

此页面让管理员管理书籍的数据,书籍管理页面见下图。此页面主要实现书籍的增加、修改、删除、查看的功能。

图5-1 书籍管理页面

5.1.2 公告信息管理

公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。下图就是公告信息管理页面。

图5.3 公告信息管理页面

5.1.3公告类型管理

公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。下图就是公告类型管理页面。

图5.4 公告类型列表页面

第6章 系统测试

程序软件的开发阶段也包括了系统测试,这个部分就是程序质量评定的一个重要环节,如果说程序通过编码实现功能之后,不通过测试检查程序中出现的错误,那么程序一旦投入生活中运行使用时,就会产生许多大大小小的错误,这个时候去解决问题已经晚了,所以一个程序在被交付给使用者使用之前,开发者就需要使用多种测试方法反复进行测试,也是对程序的一个负责表现。程序进入系统测试阶段,在讲究策略进行测试时,也需要对时效性进行把控。当开发者测试完程序,并解决完测试期间程序产生的各种错误时,就需要程序的验收方来对程序进行验收测试,这也是程序测试的最后一个操作步骤。验收测试也是对程序的质量以及可交付性方面起到关键的作用。

ZhangjieServiceImpl.java
package com.service.impl;

import com.utils.StringUtil;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.util.*;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import com.utils.PageUtils;
import com.utils.Query;
import org.springframework.web.context.ContextLoader;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import com.dao.ZhangjieDao;
import com.entity.ZhangjieEntity;
import com.service.ZhangjieService;
import com.entity.view.ZhangjieView;

/**
 * 章节 服务实现类
 */
@Service("zhangjieService")
@Transactional
public class ZhangjieServiceImpl extends ServiceImpl<ZhangjieDao, ZhangjieEntity> implements ZhangjieService {

    @Override
    public PageUtils queryPage(Map<String,Object> params) {
        if(params != null && (params.get("limit") == null || params.get("page") == null)){
            params.put("page","1");
            params.put("limit","10");
        }
        Page<ZhangjieView> page =new Query<ZhangjieView>(params).getPage();
        page.setRecords(baseMapper.selectListView(page,params));
        return new PageUtils(page);
    }


}

ShujiLiuyanServiceImpl.java
package com.service.impl;

import com.utils.StringUtil;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.util.*;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import com.utils.PageUtils;
import com.utils.Query;
import org.springframework.web.context.ContextLoader;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import com.dao.ShujiLiuyanDao;
import com.entity.ShujiLiuyanEntity;
import com.service.ShujiLiuyanService;
import com.entity.view.ShujiLiuyanView;

/**
 * 书籍留言 服务实现类
 */
@Service("shujiLiuyanService")
@Transactional
public class ShujiLiuyanServiceImpl extends ServiceImpl<ShujiLiuyanDao, ShujiLiuyanEntity> implements ShujiLiuyanService {

    @Override
    public PageUtils queryPage(Map<String,Object> params) {
        if(params != null && (params.get("limit") == null || params.get("page") == null)){
            params.put("page","1");
            params.put("limit","10");
        }
        Page<ShujiLiuyanView> page =new Query<ShujiLiuyanView>(params).getPage();
        page.setRecords(baseMapper.selectListView(page,params));
        return new PageUtils(page);
    }


}

YonghuController.java











package com.controller;

import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import com.alibaba.fastjson.JSONObject;
import java.util.*;
import org.springframework.beans.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.ContextLoader;
import javax.servlet.ServletContext;
import com.service.TokenService;
import com.utils.*;
import java.lang.reflect.InvocationTargetException;

import com.service.DictionaryService;
import org.apache.commons.lang3.StringUtils;
import com.annotation.IgnoreAuth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.entity.*;
import com.entity.view.*;
import com.service.*;
import com.utils.PageUtils;
import com.utils.R;
import com.alibaba.fastjson.*;

/**
 * 用户
 * 后端接口
 * @author
 * @email
*/
@RestController
@Controller
@RequestMapping("/yonghu")
public class YonghuController {
    private static final Logger logger = LoggerFactory.getLogger(YonghuController.class);

    @Autowired
    private YonghuService yonghuService;


    @Autowired
    private TokenService tokenService;
    @Autowired
    private DictionaryService dictionaryService;

    //级联表service

    @Autowired
    private ZuozheService zuozheService;


    /**
    * 后端列表
    */
    @RequestMapping("/page")
    public R page(@RequestParam Map<String, Object> params, HttpServletRequest request){
        logger.debug("page方法:,,Controller:{},,params:{}",this.getClass().getName(),JSONObject.toJSONString(params));
        String role = String.valueOf(request.getSession().getAttribute("role"));
        if(StringUtil.isEmpty(role))
            return R.error(511,"权限为空");
        else if("用户".equals(role))
            params.put("yonghuId",request.getSession().getAttribute("userId"));
        else if("作者".equals(role))
            params.put("zuozheId",request.getSession().getAttribute("userId"));
        if(params.get("orderBy")==null || params.get("orderBy")==""){
            params.put("orderBy","id");
        }
        PageUtils page = yonghuService.queryPage(params);

        //字典表数据转换
        List<YonghuView> list =(List<YonghuView>)page.getList();
        for(YonghuView c:list){
            //修改对应字典表字段
            dictionaryService.dictionaryConvert(c, request);
        }
        return R.ok().put("data", page);
    }

    /**
    * 后端详情
    */
    @RequestMapping("/info/{id}")
    public R info(@PathVariable("id") Long id, HttpServletRequest request){
        logger.debug("info方法:,,Controller:{},,id:{}",this.getClass().getName(),id);
        YonghuEntity yonghu = yonghuService.selectById(id);
        if(yonghu !=null){
            //entity转view
            YonghuView view = new YonghuView();
            BeanUtils.copyProperties( yonghu , view );//把实体数据重构到view中

            //修改对应字典表字段
            dictionaryService.dictionaryConvert(view, request);
            return R.ok().put("data", view);
        }else {
            return R.error(511,"查不到数据");
        }

    }

    /**
    * 后端保存
    */
    @RequestMapping("/save")
    public R save(@RequestBody YonghuEntity yonghu, HttpServletRequest request){
        logger.debug("save方法:,,Controller:{},,yonghu:{}",this.getClass().getName(),yonghu.toString());

        String role = String.valueOf(request.getSession().getAttribute("role"));
        if(StringUtil.isEmpty(role))
            return R.error(511,"权限为空");

        Wrapper<YonghuEntity> queryWrapper = new EntityWrapper<YonghuEntity>()
            .eq("username", yonghu.getUsername())
            .or()
            .eq("yonghu_phone", yonghu.getYonghuPhone())
            .or()
            .eq("yonghu_id_number", yonghu.getYonghuIdNumber())
            ;

        logger.info("sql语句:"+queryWrapper.getSqlSegment());
        YonghuEntity yonghuEntity = yonghuService.selectOne(queryWrapper);
        if(yonghuEntity==null){
            yonghu.setCreateTime(new Date());
            yonghu.setPassword("123456");
            yonghuService.insert(yonghu);
            return R.ok();
        }else {
            return R.error(511,"账户或者用户手机号或者用户身份证号已经被使用");
        }
    }

    /**
    * 后端修改
    */
    @RequestMapping("/update")
    public R update(@RequestBody YonghuEntity yonghu, HttpServletRequest request){
        logger.debug("update方法:,,Controller:{},,yonghu:{}",this.getClass().getName(),yonghu.toString());

        String role = String.valueOf(request.getSession().getAttribute("role"));
//        if(StringUtil.isEmpty(role))
//            return R.error(511,"权限为空");
        //根据字段查询是否有相同数据
        Wrapper<YonghuEntity> queryWrapper = new EntityWrapper<YonghuEntity>()
            .notIn("id",yonghu.getId())
            .andNew()
            .eq("username", yonghu.getUsername())
            .or()
            .eq("yonghu_phone", yonghu.getYonghuPhone())
            .or()
            .eq("yonghu_id_number", yonghu.getYonghuIdNumber())
            ;

        logger.info("sql语句:"+queryWrapper.getSqlSegment());
        YonghuEntity yonghuEntity = yonghuService.selectOne(queryWrapper);
        if("".equals(yonghu.getYonghuPhoto()) || "null".equals(yonghu.getYonghuPhoto())){
                yonghu.setYonghuPhoto(null);
        }
        if(yonghuEntity==null){
            //  String role = String.valueOf(request.getSession().getAttribute("role"));
            //  if("".equals(role)){
            //      yonghu.set
            //  }
            yonghuService.updateById(yonghu);//根据id更新
            return R.ok();
        }else {
            return R.error(511,"账户或者用户手机号或者用户身份证号已经被使用");
        }
    }

    /**
    * 删除
    */
    @RequestMapping("/delete")
    public R delete(@RequestBody Integer[] ids){
        logger.debug("delete:,,Controller:{},,ids:{}",this.getClass().getName(),ids.toString());
        yonghuService.deleteBatchIds(Arrays.asList(ids));
        return R.ok();
    }

    /**
     * 批量上传
     */
    @RequestMapping("/batchInsert")
    public R save( String fileName){
        logger.debug("batchInsert方法:,,Controller:{},,fileName:{}",this.getClass().getName(),fileName);
        try {
            List<YonghuEntity> yonghuList = new ArrayList<>();//上传的东西
            Map<String, List<String>> seachFields= new HashMap<>();//要查询的字段
            Date date = new Date();
            int lastIndexOf = fileName.lastIndexOf(".");
            if(lastIndexOf == -1){
                return R.error(511,"该文件没有后缀");
            }else{
                String suffix = fileName.substring(lastIndexOf);
                if(!".xls".equals(suffix)){
                    return R.error(511,"只支持后缀为xls的excel文件");
                }else{
                    URL resource = this.getClass().getClassLoader().getResource("static/upload/" + fileName);//获取文件路径
                    File file = new File(resource.getFile());
                    if(!file.exists()){
                        return R.error(511,"找不到上传文件,请联系管理员");
                    }else{
                        List<List<String>> dataList = PoiUtil.poiImport(file.getPath());//读取xls文件
                        dataList.remove(0);//删除第一行,因为第一行是提示
                        for(List<String> data:dataList){
                            //循环
                            YonghuEntity yonghuEntity = new YonghuEntity();
//                            yonghuEntity.setUsername(data.get(0));                    //账户 要改的
//                            //yonghuEntity.setPassword("123456");//密码
//                            yonghuEntity.setYonghuName(data.get(0));                    //用户姓名 要改的
//                            yonghuEntity.setYonghuPhone(data.get(0));                    //用户手机号 要改的
//                            yonghuEntity.setYonghuIdNumber(data.get(0));                    //用户身份证号 要改的
//                            yonghuEntity.setYonghuPhoto("");//照片
//                            yonghuEntity.setSexTypes(Integer.valueOf(data.get(0)));   //性别 要改的
//                            yonghuEntity.setYonghuEmail(data.get(0));                    //电子邮箱 要改的
//                            yonghuEntity.setCreateTime(date);//时间
                            yonghuList.add(yonghuEntity);


                            //把要查询是否重复的字段放入map中
                                //账户
                                if(seachFields.containsKey("username")){
                                    List<String> username = seachFields.get("username");
                                    username.add(data.get(0));//要改的
                                }else{
                                    List<String> username = new ArrayList<>();
                                    username.add(data.get(0));//要改的
                                    seachFields.put("username",username);
                                }
                                //用户手机号
                                if(seachFields.containsKey("yonghuPhone")){
                                    List<String> yonghuPhone = seachFields.get("yonghuPhone");
                                    yonghuPhone.add(data.get(0));//要改的
                                }else{
                                    List<String> yonghuPhone = new ArrayList<>();
                                    yonghuPhone.add(data.get(0));//要改的
                                    seachFields.put("yonghuPhone",yonghuPhone);
                                }
                                //用户身份证号
                                if(seachFields.containsKey("yonghuIdNumber")){
                                    List<String> yonghuIdNumber = seachFields.get("yonghuIdNumber");
                                    yonghuIdNumber.add(data.get(0));//要改的
                                }else{
                                    List<String> yonghuIdNumber = new ArrayList<>();
                                    yonghuIdNumber.add(data.get(0));//要改的
                                    seachFields.put("yonghuIdNumber",yonghuIdNumber);
                                }
                        }

                        //查询是否重复
                         //账户
                        List<YonghuEntity> yonghuEntities_username = yonghuService.selectList(new EntityWrapper<YonghuEntity>().in("username", seachFields.get("username")));
                        if(yonghuEntities_username.size() >0 ){
                            ArrayList<String> repeatFields = new ArrayList<>();
                            for(YonghuEntity s:yonghuEntities_username){
                                repeatFields.add(s.getUsername());
                            }
                            return R.error(511,"数据库的该表中的 [账户] 字段已经存在 存在数据为:"+repeatFields.toString());
                        }
                         //用户手机号
                        List<YonghuEntity> yonghuEntities_yonghuPhone = yonghuService.selectList(new EntityWrapper<YonghuEntity>().in("yonghu_phone", seachFields.get("yonghuPhone")));
                        if(yonghuEntities_yonghuPhone.size() >0 ){
                            ArrayList<String> repeatFields = new ArrayList<>();
                            for(YonghuEntity s:yonghuEntities_yonghuPhone){
                                repeatFields.add(s.getYonghuPhone());
                            }
                            return R.error(511,"数据库的该表中的 [用户手机号] 字段已经存在 存在数据为:"+repeatFields.toString());
                        }
                         //用户身份证号
                        List<YonghuEntity> yonghuEntities_yonghuIdNumber = yonghuService.selectList(new EntityWrapper<YonghuEntity>().in("yonghu_id_number", seachFields.get("yonghuIdNumber")));
                        if(yonghuEntities_yonghuIdNumber.size() >0 ){
                            ArrayList<String> repeatFields = new ArrayList<>();
                            for(YonghuEntity s:yonghuEntities_yonghuIdNumber){
                                repeatFields.add(s.getYonghuIdNumber());
                            }
                            return R.error(511,"数据库的该表中的 [用户身份证号] 字段已经存在 存在数据为:"+repeatFields.toString());
                        }
                        yonghuService.insertBatch(yonghuList);
                        return R.ok();
                    }
                }
            }
        }catch (Exception e){
            return R.error(511,"批量插入数据异常,请联系管理员");
        }
    }


    /**
    * 登录
    */
    @IgnoreAuth
    @RequestMapping(value = "/login")
    public R login(String username, String password, String captcha, HttpServletRequest request) {
        YonghuEntity yonghu = yonghuService.selectOne(new EntityWrapper<YonghuEntity>().eq("username", username));
        if(yonghu==null || !yonghu.getPassword().equals(password))
            return R.error("账号或密码不正确");
        //  // 获取监听器中的字典表
        // ServletContext servletContext = ContextLoader.getCurrentWebApplicationContext().getServletContext();
        // Map<String, Map<Integer, String>> dictionaryMap= (Map<String, Map<Integer, String>>) servletContext.getAttribute("dictionaryMap");
        // Map<Integer, String> role_types = dictionaryMap.get("role_types");
        // role_types.get(.getRoleTypes());
        String token = tokenService.generateToken(yonghu.getId(),username, "yonghu", "用户");
        R r = R.ok();
        r.put("token", token);
        r.put("role","用户");
        r.put("username",yonghu.getYonghuName());
        r.put("tableName","yonghu");
        r.put("userId",yonghu.getId());
        return r;
    }

    /**
    * 注册
    */
    @IgnoreAuth
    @PostMapping(value = "/register")
    public R register(@RequestBody YonghuEntity yonghu){
//    	ValidatorUtils.validateEntity(user);
        Wrapper<YonghuEntity> queryWrapper = new EntityWrapper<YonghuEntity>()
            .eq("username", yonghu.getUsername())
            .or()
            .eq("yonghu_phone", yonghu.getYonghuPhone())
            .or()
            .eq("yonghu_id_number", yonghu.getYonghuIdNumber())
            ;
        YonghuEntity yonghuEntity = yonghuService.selectOne(queryWrapper);
        if(yonghuEntity != null)
            return R.error("账户或者用户手机号或者用户身份证号已经被使用");
        yonghu.setCreateTime(new Date());
        yonghuService.insert(yonghu);
        return R.ok();
    }

    /**
     * 重置密码
     */
    @GetMapping(value = "/resetPassword")
    public R resetPassword(Integer  id){
        YonghuEntity yonghu = new YonghuEntity();
        yonghu.setPassword("123456");
        yonghu.setId(id);
        yonghuService.updateById(yonghu);
        return R.ok();
    }


    /**
     * 忘记密码
     */
    @IgnoreAuth
    @RequestMapping(value = "/resetPass")
    public R resetPass(String username, HttpServletRequest request) {
        YonghuEntity yonghu = yonghuService.selectOne(new EntityWrapper<YonghuEntity>().eq("username", username));
        if(yonghu!=null){
            yonghu.setPassword("123456");
            boolean b = yonghuService.updateById(yonghu);
            if(!b){
               return R.error();
            }
        }else{
           return R.error("账号不存在");
        }
        return R.ok();
    }


    /**
    * 获取用户的session用户信息
    */
    @RequestMapping("/session")
    public R getCurrYonghu(HttpServletRequest request){
        Integer id = (Integer)request.getSession().getAttribute("userId");
        YonghuEntity yonghu = yonghuService.selectById(id);
        if(yonghu !=null){
            //entity转view
            YonghuView view = new YonghuView();
            BeanUtils.copyProperties( yonghu , view );//把实体数据重构到view中

            //修改对应字典表字段
            dictionaryService.dictionaryConvert(view, request);
            return R.ok().put("data", view);
        }else {
            return R.error(511,"查不到数据");
        }
    }


    /**
    * 退出
    */
    @GetMapping(value = "logout")
    public R logout(HttpServletRequest request) {
        request.getSession().invalidate();
        return R.ok("退出成功");
    }




    /**
    * 前端列表
    */
    @IgnoreAuth
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params, HttpServletRequest request){
        logger.debug("list方法:,,Controller:{},,params:{}",this.getClass().getName(),JSONObject.toJSONString(params));

        // 没有指定排序字段就默认id倒序
        if(StringUtil.isEmpty(String.valueOf(params.get("orderBy")))){
            params.put("orderBy","id");
        }
        PageUtils page = yonghuService.queryPage(params);

        //字典表数据转换
        List<YonghuView> list =(List<YonghuView>)page.getList();
        for(YonghuView c:list)
            dictionaryService.dictionaryConvert(c, request); //修改对应字典表字段
        return R.ok().put("data", page);
    }

    /**
    * 前端详情
    */
    @RequestMapping("/detail/{id}")
    public R detail(@PathVariable("id") Long id, HttpServletRequest request){
        logger.debug("detail方法:,,Controller:{},,id:{}",this.getClass().getName(),id);
        YonghuEntity yonghu = yonghuService.selectById(id);
            if(yonghu !=null){


                //entity转view
                YonghuView view = new YonghuView();
                BeanUtils.copyProperties( yonghu , view );//把实体数据重构到view中

                //修改对应字典表字段
                dictionaryService.dictionaryConvert(view, request);
                return R.ok().put("data", view);
            }else {
                return R.error(511,"查不到数据");
            }
    }


    /**
    * 前端保存
    */
    @RequestMapping("/add")
    public R add(@RequestBody YonghuEntity yonghu, HttpServletRequest request){
        logger.debug("add方法:,,Controller:{},,yonghu:{}",this.getClass().getName(),yonghu.toString());
        Wrapper<YonghuEntity> queryWrapper = new EntityWrapper<YonghuEntity>()
            .eq("username", yonghu.getUsername())
            .or()
            .eq("yonghu_phone", yonghu.getYonghuPhone())
            .or()
            .eq("yonghu_id_number", yonghu.getYonghuIdNumber())
            ;
        logger.info("sql语句:"+queryWrapper.getSqlSegment());
        YonghuEntity yonghuEntity = yonghuService.selectOne(queryWrapper);
        if(yonghuEntity==null){
            yonghu.setCreateTime(new Date());
        yonghu.setPassword("123456");
        //  String role = String.valueOf(request.getSession().getAttribute("role"));
        //  if("".equals(role)){
        //      yonghu.set
        //  }
        yonghuService.insert(yonghu);
            return R.ok();
        }else {
            return R.error(511,"账户或者用户手机号或者用户身份证号已经被使用");
        }
    }


}

register.vue
<template>
    <div>
        <div class="container">
            <div class="login-form" style="backgroundColor:rgba(183, 174, 174, 0.5);borderRadius:22px">
                <h1 class="h1" style="color:#000;fontSize:28px;">文学作品网站注册</h1>
                <el-form ref="rgsForm" class="rgs-form" :model="rgsForm" label-width="120px">
                        <el-form-item label="账号" class="input">
                            <el-input v-model="ruleForm.username" autocomplete="off" placeholder="账号"  />
                        </el-form-item>
                        <el-form-item label="密码" class="input">
                            <el-input type="password" v-model="ruleForm.password" autocomplete="off" show-password/>
                        </el-form-item>
                        <el-form-item label="重复密码" class="input">
                            <el-input type="password" v-model="ruleForm.repetitionPassword" autocomplete="off" show-password/>
                        </el-form-item>
                        <el-form-item label="用户姓名" class="input" v-if="tableName=='yonghu'">
                            <el-input v-model="ruleForm.yonghuName" autocomplete="off" placeholder="用户姓名"  />
                        </el-form-item>
                        <el-form-item label="用户手机号" class="input" v-if="tableName=='yonghu'">
                            <el-input v-model="ruleForm.yonghuPhone" autocomplete="off" placeholder="用户手机号"  />
                        </el-form-item>
                        <el-form-item label="用户身份证号" class="input" v-if="tableName=='yonghu'">
                            <el-input v-model="ruleForm.yonghuIdNumber" autocomplete="off" placeholder="用户身份证号"  />
                        </el-form-item>
                        <el-form-item label="电子邮箱" class="input" v-if="tableName=='yonghu'">
                            <el-input v-model="ruleForm.yonghuEmail" autocomplete="off" placeholder="电子邮箱"  />
                        </el-form-item>
                        <el-form-item label="作者姓名" class="input" v-if="tableName=='zuozhe'">
                            <el-input v-model="ruleForm.zuozheName" autocomplete="off" placeholder="作者姓名"  />
                        </el-form-item>
                        <el-form-item label="作者手机号" class="input" v-if="tableName=='zuozhe'">
                            <el-input v-model="ruleForm.zuozhePhone" autocomplete="off" placeholder="作者手机号"  />
                        </el-form-item>
                        <el-form-item label="作者身份证号" class="input" v-if="tableName=='zuozhe'">
                            <el-input v-model="ruleForm.zuozheIdNumber" autocomplete="off" placeholder="作者身份证号"  />
                        </el-form-item>
                        <el-form-item label="电子邮箱" class="input" v-if="tableName=='zuozhe'">
                            <el-input v-model="ruleForm.yonghuEmail" autocomplete="off" placeholder="电子邮箱"  />
                        </el-form-item>
                        <div style="display: flex;flex-wrap: wrap;width: 100%;justify-content: center;">
                            <el-button class="btn" type="primary" @click="login()">注册</el-button>
                            <el-button class="btn close" type="primary" @click="close()">取消</el-button>
                        </div>
                </el-form>
            </div>
        </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                ruleForm: {
                },
                tableName:"",
                rules: {},
                sexTypesOptions : [],
            };
        },
        mounted(){
            let table = this.$storage.get("loginTable");
            this.tableName = table;
        },
        methods: {
            // 获取uuid
            getUUID () {
                return new Date().getTime();
            },
            close(){
                this.$router.push({ path: "/login" });
            },
            // 注册
            login() {

                            if((!this.ruleForm.username)){
                                this.$message.error('账号不能为空');
                                return
                            }
                            if((!this.ruleForm.password)){
                                this.$message.error('密码不能为空');
                                return
                            }
                            if((!this.ruleForm.repetitionPassword)){
                                this.$message.error('重复密码不能为空');
                                return
                            }
                            if(this.ruleForm.repetitionPassword != this.ruleForm.password){
                                this.$message.error('密码和重复密码不一致');
                                return
                            }
                            if((!this.ruleForm.yonghuName)&& 'yonghu'==this.tableName){
                                this.$message.error('用户姓名不能为空');
                                return
                            }
                             if('yonghu' == this.tableName && this.ruleForm.yonghuPhone&&(!this.$validate.isMobile(this.ruleForm.yonghuPhone))){
                                 this.$message.error('手机应输入手机格式');
                                 return
                             }
                            if((!this.ruleForm.yonghuIdNumber)&& 'yonghu'==this.tableName){
                                this.$message.error('用户身份证号不能为空');
                                return
                            }
                            if('yonghu' == this.tableName && this.ruleForm.yonghuEmail&&(!this.$validate.isEmail(this.ruleForm.yonghuEmail))){
                                this.$message.error("邮箱应输入邮件格式");
                                return
                            }
                             if('zuozhe' == this.tableName && this.ruleForm.zuozhePhone&&(!this.$validate.isMobile(this.ruleForm.zuozhePhone))){
                                 this.$message.error('手机应输入手机格式');
                                 return
                             }
                            if((!this.ruleForm.zuozheIdNumber)&& 'zuozhe'==this.tableName){
                                this.$message.error('作者身份证号不能为空');
                                return
                            }
                            if('zuozhe' == this.tableName && this.ruleForm.yonghuEmail&&(!this.$validate.isEmail(this.ruleForm.yonghuEmail))){
                                this.$message.error("邮箱应输入邮件格式");
                                return
                            }
                this.$http({
                    url: `${this.tableName}/register`,
                    method: "post",
                    data:this.ruleForm
                }).then(({ data }) => {
                    if (data && data.code === 0) {
                    this.$message({
                        message: "注册成功,请登录后在个人中心页面补充个人数据",
                        type: "success",
                        duration: 1500,
                        onClose: () => {
                        this.$router.replace({ path: "/login" });
                }
                });
                } else {
                    this.$message.error(data.msg);
                }
            });
            }
        }
    };
</script>
<style lang="scss" scoped>
    .el-radio__input.is-checked .el-radio__inner {
        border-color: #00c292;
        background: #00c292;
    }

    .el-radio__input.is-checked .el-radio__inner {
        border-color: #00c292;
        background: #00c292;
    }

    .el-radio__input.is-checked .el-radio__inner {
        border-color: #00c292;
        background: #00c292;
    }

    .el-radio__input.is-checked+.el-radio__label {
        color: #00c292;
    }

    .el-radio__input.is-checked+.el-radio__label {
        color: #00c292;
    }

    .el-radio__input.is-checked+.el-radio__label {
        color: #00c292;
    }

    .h1 {
        margin-top: 10px;
    }

    body {
        padding: 0;
        margin: 0;
    }

    // .container {
       //    min-height: 100vh;
       //    text-align: center;
       //    // background-color: #00c292;
       //    padding-top: 20vh;
       //    background-image: url(../assets/img/bg.jpg);
       //    background-size: 100% 100%;
       //    opacity: 0.9;
       //  }

    // .login-form:before {
       // 	vertical-align: middle;
       // 	display: inline-block;
       // }

    // .login-form {
       // 	max-width: 500px;
       // 	padding: 20px 0;
       // 	width: 80%;
       // 	position: relative;
       // 	margin: 0 auto;

    // 	.label {
          // 		min-width: 60px;
          // 	}

    // 	.input-group {
          // 		max-width: 500px;
          // 		padding: 20px 0;
          // 		width: 80%;
          // 		position: relative;
          // 		margin: 0 auto;
          // 		display: flex;
          // 		align-items: center;

    // 		.input-container {
              // 			display: inline-block;
              // 			width: 100%;
              // 			text-align: left;
              // 			margin-left: 10px;
              // 		}

    // 		.icon {
              // 			width: 30px;
              // 			height: 30px;
              // 		}

    // 		.input {
              // 			position: relative;
              // 			z-index: 2;
              // 			float: left;
              // 			width: 100%;
              // 			margin-bottom: 0;
              // 			box-shadow: none;
              // 			border-top: 0px solid #ccc;
              // 			border-left: 0px solid #ccc;
              // 			border-right: 0px solid #ccc;
              // 			border-bottom: 1px solid #ccc;
              // 			padding: 0px;
              // 			resize: none;
              // 			border-radius: 0px;
              // 			display: block;
              // 			width: 100%;
              // 			height: 34px;
              // 			padding: 6px 12px;
              // 			font-size: 14px;
              // 			line-height: 1.42857143;
              // 			color: #555;
              // 			background-color: #fff;
              // 		}

    // 	}
    // }

    .nk-navigation {
        margin-top: 15px;

    a {
        display: inline-block;
        color: #fff;
        background: rgba(255, 255, 255, .2);
        width: 100px;
        height: 50px;
        border-radius: 30px;
        text-align: center;
        display: flex;
        align-items: center;
        margin: 0 auto;
        justify-content: center;
        padding: 0 20px;
    }

    .icon {
        margin-left: 10px;
        width: 30px;
        height: 30px;
    }
    }

    .register-container {
        margin-top: 10px;

    a {
        display: inline-block;
        color: #fff;
        max-width: 500px;
        height: 50px;
        border-radius: 30px;
        text-align: center;
        display: flex;
        align-items: center;
        margin: 0 auto;
        justify-content: center;
        padding: 0 20px;

    div {
        margin-left: 10px;
    }
    }
    }

    .container {
        background-image: url("http://codegen.caihongy.cn/20210413/1043288468a242e083bddea1af7df208.jpg");
        height: 100vh;
        background-position: center center;
        background-size: cover;
        background-repeat: no-repeat;

    .login-form {
        right: 50%;
        top: 50%;
        height: auto;
        transform: translate3d(50%, -50%, 0);
        border-radius: 10px;
        background-color: rgba(255,255,255,.5);
        width: 420px;
        padding: 30px 30px 40px 30px;
        font-size: 14px;
        font-weight: 500;

    .h1 {
        margin: 0;
        text-align: center;
        line-height: 54px;
        font-size: 24px;
        color: #000;
    }

    .rgs-form {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;

    .input {
        width: 100%;

    & /deep/ .el-form-item__label {
          line-height: 40px;
          color: rgba(17, 16, 16, 1);
          font-size: #606266;
      }

    & /deep/ .el-input__inner {
          height: 40px;
          color: rgba(23, 24, 26, 1);
          font-size: 14px;
          border-width: 1px;
          border-style: solid;
          border-color: #606266;
          border-radius: 22px;
          background-color: #fff;
      }
    }

    .btn {
        margin: 0 10px;
        width: 88px;
        height: 44px;
        color: #fff;
        font-size: 14px;
        border-width: 1px;
        border-style: solid;
        border-color: #409EFF;
        border-radius: 22px;
        background-color: #409EFF;
    }

    .close {
        margin: 0 10px;
        width: 88px;
        height: 44px;
        color: #409EFF;
        font-size: 14px;
        border-width: 1px;
        border-style: solid;
        border-color: #409EFF;
        border-radius: 22px;
        background-color: #FFF;
    }

    }
    }
    }
</style>

声明

本博客适用于广泛的学术和教育用途,包括但不限于个人学习、开发设计,产品设计。仅供学习参考,旨在为读者提供深入理解和学术研究的材料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值