【无标题】

 SOAWeb service技术》

实验及课程期末大作业

  2024年    6月   13日

评分标准

序号

评分内容

得分

1

文档的规范(40分)

遵照实验和大作业模板进行规范编写。

字体,字号,行距正确;图表格式规范;文字通顺,文本清晰美观。

报告结构完整,能正确使用类图,顺序图,状态图,时序图等图形化手段对系统进行设计与描述。

采用面向服务的思想进行设计,报告中具有服务的架构图,服务之间的调用关系,服务的接口设计等。

2

实践期间的表现(10分)

学习态度端正,按时上交完整文档和源码。

3

实验以及大作业的完成度与正确性(40分)

完成全部实验;完成每个实验的各项要求。

完成选定的大作业,完成大作业的主要功能。

代码能正确运行。

4

其它(10分):

1、根据项目需求合理选择及使用数据库或文件系统;并在报告中正确描述文件系统或数据库的设计与使用。

2、根据项目需求合理选择及使用其他相关技术,并在报告中正确描述相关技术的设计与使用。

3、界面设计完整。

总分:

实验题目      实验一 创建基于SOAP的Web Service                  

一、实验目的

1、掌握创建一个基于SOAP的Web服务的基本流程;

2、掌握查看Web服务描述文档的方法;

3、创建客户端使用服务。

二、实验内容和要求

1、使用Java创建一个基于SOAP的Web服务,查看对应的WSDL文档和创建客户端使用服务。

2、学习使用基于JWS的web service和Apache CXF的web service。

三、实验主要仪器设备和材料

1.计算机及操作系统:PC机,Windows xp/7;

2.编辑及运行环境: Eclipse,Tomcat,JDK 1.8

四、实验方法、步骤及结果测试

创建基于JWS的Web Service

1创建基于JWS的Web Service,命名为JWSof****,其中星号部分用姓名的拼音取代(姓写全拼,名写首字母,如JWSofSongW)。该服务有一个方法string JWSHello**(string),其中星号部分用姓名取代(编码规则同上),该方法接收学号string作为输入,输出个人的基本信息string,如学院,班级,姓名,籍贯。

项目结构:

项目结构截图显示

说明:在集成开发环境Eclipse,IntelliJ IDEA中将整个工程项目结构截图

项目结构说明

说明:

说明项目中每个文件的作用,包括配置文件等。这一部分不能省略,一定要对截图中内容进行说明。

out 是项目的编译后的输出文件

src 是项目的编写代码的文件

src.WebService是基于JWS的设计的软件包

src.WebService.Client是客户的端的代码文件

src.WebService.JWSHelloZhuZ是方法的接口

src.WebService.JWSHelloZhuZImpl是方法的实现

src.WebService.ServiceMain是服务端的代码文件

实现代码及截图:

实现代码

说明:

1此处贴上实现的关键代码,并且中需要写上注释说明语句的作用

2 如果有多个文件需要分别说明

//ServiceMain的文件客户端方法发布

Endpoint.publish("http://localhost:8888/WebService" , new JWSHelloZhuZImpl());

截图显示

说明:

截图需要将完整代码截取出来

//ServiceMain文件

//JWSHelloZhuZ文件

//JWSHelloZhuZImpl文件

2、服务的部署和配置

截图:

具体的截图内容根据各自采用的实现方案自行截图,可以是代码部署,可以是配置文件部署,也可以是图形对话框部署

对截图内容的文字说明:

这一部分不能省略,一定要对截图中内容进行说明

采用代码部署的方式,通过EndPoint接口方法进行部署,地址为本地localhost,端口号为8888,发布方法为JWSHellloZhuZImpl类种的所有方法。

3、在浏览器中查看该Web服务的描述文档

截图:

结合自己编写的web服务,说明该服务的WSDL文档中各元素与服务之间的对应关系。

definitions>元素:这是WSDL文档的根元素,定义了整个服务的结构。

<message>元素:定义了操作所使用的消息的结构tns:HelloZhuZ。

<portType>元素:描述了服务的操作HelloZhuZ,即可用的方法。

<service>元素:定义了服务的名称JWSHelloZhuZImplService和可访问的端点JWSHelloZhuZImplPort

4、产生客户端代理

截图:

对截图内容的文字说明:

这一部分不能省略,一定要对截图中内容进行说明

手动创建客户端代理文件

5、创建客户端

截图:

对截图内容的文字说明:

这一部分不能省略,一定要对截图中内容进行说明

通过Service.create创建客户端地址为http://localhost:8888/WebService?wsdl,获取端口的JWSHelloZhuZ的方法,最后调用HelloZhuZ方法参数为“3121004801”

创建基于Apache CXF的web service

1、创建基于Apache CXF的web service,命名为CXFof****,其中星号部分用姓名的拼音取代(姓写全拼,名写首字母,如CXFofSongW)。该服务有一个方法string CXFHello**(string),其中星号部分用姓名取代(编码规则同上),该方法接收学号string作为输入,输出个人的基本信息string,如学院,班级,姓名,籍贯。

项目结构:

项目结构截图显示

说明:在集成开发环境Eclipse,IntelliJ IDEA中将整个工程项目结构截图

项目结构说明

说明:

说明项目中每个文件的作用,包括配置文件等。这一部分不能省略,一定要对截图中内容进行说明。

idea文件是IDEA工程自带文件

src是项目存放代码文件

taget是存放编译生成文件的文件

pom.xml是项目依赖文件

实现代码及截图:

实现代码

说明:

1此处贴上实现的关键代码,并且中需要写上注释说明语句的作用

2 如果有多个文件需要分别说明

//ServiceMain文件的服务端发布

CXFHelloZhuZImpl serviceImpl = new CXFHelloZhuZImpl();

  JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();

  // 设置服务地址

  factory.setAddress("http://localhost:8888/CXFofZhuZ");// 设置服务实现类

  factory.setServiceBean(serviceImpl);

  // 发布服务

  factory.create();

截图显示

说明:

截图需要将完整代码截取出来

//ServiceMain文件

//CXFHelloZhuZ文件

// CXFHelloZhuZImpl文件

2、服务的部署和配置

截图:

具体的截图内容根据各自采用的实现方案自行截图,可以是代码部署,可以是配置文件部署,也可以是图形对话框部署

对截图内容的文字说明:

这一部分不能省略,一定要对截图中内容进行说明

采用代码部署,通过创建JaxWsServerFactoryBeab类来设置地址http://localhost:8888/CXFofZhuZ,并设置方法,并进一步发布。

3、在浏览器中查看该Web服务的描述文档

截图:

结合自己编写的web服务,说明该服务的WSDL文档中各元素与服务之间的对应关系。

4、创建客户端

截图:

对截图内容的文字说明:

这一部分不能省略,一定要对截图中内容进行说明

使用JaxWsProxyFactoryBean创建客户端代理对象,并创建远程服务的代理对象,然后调用远程服务的方法。

实验题目 实验二  创建RESTful服务端和客户端             

一、实验目的

掌握使用Jersey框架创建RESTful风格的服务端,并创建客户端程序。

掌握使用spring boot创建RESTful风格的服务端,并创建客户端程序

(二选一)

二、实验内容和要求

1、创建服务端程序resourceof***,其中星号部分用姓名的拼音取代(姓写全拼,名写首字母,如resourceofSongW)。使用post注解资源接口用于增加一个学生的学号,姓名,出生年月等信息;使用get注解资源接口用于获得所有学生的信息;使用get注解的资源接口用于获得指定学号的学生信息。

2、创建客户端程序clientof***,其中星号部分用姓名的拼音取代(姓写全拼,名写首字母,如clientofSongW)。访问服务,实现增加多个学生的信息,并输出所有学生的信息,以及指定学号的学生信息。

3、根据需要创建相应的配置文件以及一些辅助类。

三、实验主要仪器设备和材料

1.计算机及操作系统:PC机,Windows xp/7;

2.编辑及运行环境: Eclipse juno ,Tomcat8.0,JDK 1.8

四、实验方法、步骤及结果测试

1、创建项目,项目命名为 REST***,其中星号部分用姓名的拼音取代(姓写全拼,名写首字母),按个各人习惯建好包。

截图展现项目文件目录结构

分别说明文件夹,包,类,配置文件的作用(这一部分不能省略,一定要对截图中内容进行说明

idea为IDEA项目工程配置文件

src代码文件

target为代码编译生成存放文件

2、创建服务端程序resourceof***。

截图展现关键代码

//ResourcefZhuZ文件

解释(这一部分不能省略,一定要对截图中内容进行说明,特别要列出服务接口的设计

通过spring boot创建风格的服务端

3、(如果有)请给出服务端的辅助类,解释其核心代码。

截图展现关键辅助类及核心代码

解释(这一部分不能省略,一定要对截图中内容进行说明

4、请给出配置文件代码,并解释核心内容。

截图展现配置文件代码

//StudentControllar文件

解释(这一部分不能省略,一定要对截图中内容进行说明

定义服务接口

@PostMapping("/AddStudents")

Post请求,添加student

@GetMapping("/GetStudents")
Get请求。返回student数组
@GetMapping("/GetAllStudents")
Get请求,输出所有student
@GetMapping("/GetStudent")
Get请求,输出指定的student

5、在浏览器中访问所写的RESTful资源接口,测试RESTful资源是否能被访问。

截图展现浏览器中的运行结果

解释(要求分析浏览器中的URI)(这一部分不能省略,一定要对截图中内容进行说明

测试GetStudent请求,请求学号为3121004810,数据中没有学号为3121004801的学生,输出结果

6、创建客户端程序clientof***。

截图展现关键代码

解释(这一部分不能省略,一定要对截图中内容进行说明,特别说明客户端是如何访问到服务方法的

定义函数

public static void addMStudents
用来添加多个学生
public static void getAllStudents
输出所有学生
public static void getStudent

输出指定学生

截图展现运行结果

解释(这一部分不能省略,一定要对截图中内容进行说明

在主函数中添加了两个学生:

"3121004801", "XieBF", "2003-04-23"

"3121004805", "吉吉", "2002-08-08"

然后输出两个学生

最后在输出学号为“3121004810”的学生

实验题目        实验三 对SOAP消息包的操作                 

一、实验目的

    掌握使用Java提供的handler机制对封装的SOAP消息报进行操作,加深对SOAP的理解。

二、实验内容和要求

1、使用Java提供的handler机制在客户端对SOAP请求包注入header。在实验一建立的web服务的基础上,对客户端产生的SOAP请求包加入header,header有一个子元素student,命名空间为你自己项目使用的命名空间;student有三个子元素sno和sname、time,即学号,姓名和当前系统时间。参考如下形式:

<SOAP-ENV:Header>

<student xmlns="http://hello.soapHandlerEx/">

<sno>001</sno>

<sname>你的名字</sname>

<time>2024/5/10</time>

</student>

</SOAP-ENV:Header>

输出方式可以采用命令行或文本记录。

2、在服务端对SOAP请求包进行解析,获得头部,并展示出头部的信息,展示方式可以自行设计。

三、实验主要仪器设备和材料

1.计算机及操作系统:PC机,Windows xp/7;

2.编辑及运行环境:visual studio 2010,IIS Express;Eclipse,Tomcat,JDK 1.8

四、实验方法、步骤及结果测试

1、展现项目文件目录结构,并解释每个文件的作用。

截图展现项目文件目录结构

分别说明文件夹,包,类,配置文件的作用

(这一部分不能省略,一定要对截图中内容进行说明)

src.main.java文件是代码的仓库

target存放代码编译生成的文件

2、请给出关键服务端类,并解释其核心代码。

截图展现关键服务端的类及核心代码

解释:

(这一部分不能省略,一定要对截图中内容进行说明)

采用代码部署,通过创建JaxWsServerFactoryBeab类来设置地http://localhost:8888/CXFofXieBF,设置服务端的handler并设置方法,并进一步发布。

3、服务端handler的设计

截图展现类及核心代码

解释:

(这一部分不能省略,一定要对截图中内容进行说明)

4、服务端配置文件

截图展现类及核心代码

//pom.xml文件

//ServiceMain文件

//ServiceSOAPHandler文件

解释:

(这一部分不能省略,一定要对截图中内容进行说明)

Maven工程的基本工作单元,是一个XML(可扩展标记语言)文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。执行任务或目标时,Maven会在当前目录中查找 POM并读取从而获取所需的配置信息执行目标,属于项目级别的配置文件。

5、请给出关键客户端类,并解释其核心代码。

截图展现关键客户端的类及核心代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

首先,定义了远程服务的地址,其值为"http://localhost:8888/CXFofZhuZ"。

使用JaxWsProxyFactoryBean创建客户端代理对象。JaxWsProxyFactoryBean是Apache CXF框架提供的一个类,用于创建Web服务的客户端代理。

通过设置serviceClass属性,指定了服务接口的类型,即CXFHelloZhuZ.class。这是远程服务的接口定义。

通过设置address属性,指定了远程服务的地址。

通过factory.getHandlers().add(new InfoHandler()),添加了一个InfoHandler处理器对象。处理器可以在请求和响应之前对消息进行处理,例如添加头部信息。

使用factory.create()创建了远程服务的代理对象service,类型为CXFHelloZhuZ。

调用远程服务的方法HelloZhuZ,并传递参数"3121004805"。

将返回结果存储在result变量中。

最后,打印调用结果到控制台,输出字符串为"调用结果:"后面跟着result的值。

这段代码的主要目的是创建一个客户端代理对象,调用远程服务的方法,并处理返回结果。需要注意的是,这段代码依赖于Apache CXF框架,可能需要在项目中添加相应的依赖库才能正常运行。

6、客户端handler的设计

截图展现类及核心代码

解释:

(这一部分不能省略,一定要对截图中内容进行说明)方法开始时,在控制台打印"接收信息"。

从SOAPMessageContext对象中获取MessageContext.MESSAGE_OUTBOUND_PROPERTY属性的值,并将其赋给outboundProperty变量。

如果outboundProperty为true,则代码继续修改SOAP消息。

从SOAPMessageContext对象中获取SOAP消息。

从SOAP消息中获取SOAP信封和SOAP头部。

如果SOAP头部为null,则向SOAP信封添加一个新的头部。

在控制台打印"添加头部"。

创建一个具有命名空间为"http://localhost:8888/CXFofZhuZ"的限定名称为"student"的新SOAP元素,并将其作为子元素添加到SOAP头部。

创建学生元素的子元素,分别为"sno"、"sname"和"time",并设置它们的文本内容。

使用LocalDateTime类将timeElement设置为当前日期和时间,并使用"yyyy/MM/dd"的格式进行格式化。

如果在代码块的执行过程中发生异常,它将被捕获,并将异常堆栈跟踪打印到控制台。

最后,方法返回true。

7、客户端配置文件,并解释核心内容。

截图展现配置文件代码

//pom.xml文件

//Client文件

//InfoHandler文件

解释

(这一部分不能省略,一定要对截图中内容进行说明)

Maven工程的基本工作单元,是一个XML(可扩展标记语言)文件,包含了项目的基本信息,用于描述项目如何构建,声明项目依赖等等。执行任务或目标时,Maven会在当前目录中查找 POM并读取从而获取所需的配置信息执行目标,属于项目级别的配置文件。

8、运行结果并解释

截图展现运行结果(客户端)

解释

(这一部分不能省略,一定要对截图中内容进行说明)

客户端调用远程服务的方法,打印调用结果

截图展现运行结果(服务端)

解释

(这一部分不能省略,一定要对截图中内容进行说明)

服务端开启,等待客户端调用远程服务的方法,打印客户端信息

五、实验中出现的问题及解决方案

六、参考材料

https://my.oschina.net/fhd/blog/222157

https://my.oschina.net/fhd/blog/222324

https://my.oschina.net/fhd/blog/261119

QName,SOAPHeaderElement,SOAPElement相关类和方法的使用

实验题目 实验四 基于Srping boot和Spring cloud构建微服务                 

一、实验目的

    掌握使用Spring Cloud + Spring Boot构建微服务,建立分布式注册中心,进行分布式通信和设置分布式断路器。

二、实验内容和要求

  1、具体每个服务完成的任务可以自行选择,设计的服务的关系只需能满足上图的要求,可以是订单服务,用户服务,书籍服务等,不需要使用数据库。

2、每一个服务是一个Spring boot应用程序。将所有服务在注册中心注册(可使用Spring Cloud consul)。

    3、根据上述关系进行服务的调用(可使用Spring Cloud Feign)。

4、使用Spring Cloud Ribbon进行负载均衡。

5、使用Hystrix进行断路保护。

6、运行结果的展示要带有个人信息,以避免抄袭。

三、实验主要仪器设备和材料

1.计算机及操作系统:PC机,Windows xp/7;

2.编辑及运行环境: Eclipse,Tomcat,JDK 1.8,IntelliJ IDEA,Spring boot和Spring cloud

四、实验方法、步骤及结果测试

1、展现3个服务的项目文件目录结构,并解释每个文件的作用。

截图展现项目文件目录结构(A服务)

(只截图A1的文件目录,与A2和A3相同)

分别说明文件夹,包,类,配置文件的作用

(这一部分不能省略,一定要对截图中内容进行说明)

pom.xml为文件的环境配置文件,application.yml为微服务的配置文件,InfoControlled是微服务的具体操作函数,OutService是调用其他服务的接口,InfoHystrix是断路保护相应的执行函数。

截图展现项目文件目录结构(B服务)

分别说明文件夹,包,类,配置文件的作用

(这一部分不能省略,一定要对截图中内容进行说明)

pom.xml为文件的环境配置文件,application.yml为微服务的配置文件,LoginControlled是微服务的具体操作函数,InfoService是调用其他服务的接口。UserRibbonConfig是负载均衡的具体方法的类。

截图展现项目文件目录结构(C服务)

分别说明文件夹,包,类,配置文件的作用

(这一部分不能省略,一定要对截图中内容进行说明)

pom.xml为文件的环境配置文件,application.yml为微服务的配置文件,FinallyControlled是微服务的具体操作函数。

2、说明服务A的功能设计,并解释其核心代码。

服务功能设计及核心代码

解释:

(这一部分不能省略,一定要对截图中内容进行说明)

通过application.yml文件配置注册到consul微服务的信息。

通过info函数返回用户的年龄信息,通过OutService接口调用CloudC的微服务(为了方便测试选择GET方法进行测试)

3、说明服务B的功能设计,并解释其核心代码。

服务功能设计及核心代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

通过application.yml文件配置注册到consul微服务的信息。

通过login函数进行用户的登录,通过InfoService接口调用CloudA的微服务(为了方便测试选择GET方法进行测试)

4、说明服务C的功能设计,并解释其核心代码。

服务功能设计及核心代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

通过application.yml文件配置注册到consul微服务的信息。

通过out函数用户的退出。(为了方便测试选择GET方法进行测试)

5、与服务调用相关的代码,并解释核心内容。

截图展现代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

InfoService的接口,通过Feign对CloudA微服务的调用进行封装,通过函数info对CloudA中的/info服务进行调用

OutService的接口,通过Feign对CloudC微服务的调用进行封装,通过函数out对CloudC中的/out服务进行调用

6、与负载均衡相关的代码,并解释核心内容

截图展现代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

通过@RibbonClients和@RibbonClient注解实现对CloudA微服务的负载均衡,UserRibbonConfig类是负载均衡策略,使用的是轮询的策略。

7、与断路保护相关的代码,并解释核心内容

截图展现代码

解释

(这一部分不能省略,一定要对截图中内容进行说明)

在@FeignClient注解中添加fallback和对应相应的断路保护类InfoHystrix ,InfoHystrix继承自InfoService接口,在断路时返回over time。

8、运行结果并解释(运行的访问入口从服务B开始,由此引发后面对其它服务的调用)

截图展现运行结果

Consul上的结果

CloudB的测试(轮询的结果不同)

CloudA1的测试

CloudC的测试

断路保护

解释

(这一部分不能省略,一定要对截图中内容进行说明)

通过http://localhost:8511/login测试CloudB返回Login Successful是CloudB产生的微服务,age:24是CloudsA微服务返回的结果,User out是微服务CloudC返回的结果,刷新页面有三个不同的age分别是22,23,24,是通过轮询调用有coudA1,coudA2和coudA3的结果。

通过http://localhost:8514/info测试CloudA1

通过http://localhost:8513/out测试CloudC

在不开启CloudA的情况下,开启CloudB,出现time over断路保护。

五、实验中出现的问题及解决方案

问题:各依赖的版本对不上

描述:例子一,@EnableCircuitBreaker在不同的版本的依赖中已经由@ EnableHystrix代替

解决:使用相应的版本和相应的注解

六、参考材料

教材第2,3,4,5章内容

智慧农业管理系统的设计与实现

1 课题背景

2 需求分析

  1. 解决专家问答问题:专家点击解决按钮,输入问题解决方案,用来解决用户向专家提出的问题。
  2. 管理专家问答:管理专家问答的增删改查,设置管理专家问答数据的公开情况
  3. 管理科普文章:管理科普文章的增删改查,后台管理用户管理科普文章的是否推荐,是否公开,查询用户对文章点赞情况
  4. 向专家提问:后台管理用户向专家的提问,以及专家对问题的回答,后台管理员可以对问题和回答经行增删改查操作
  5. 科普文章:用户查看科普文章,可在后台对科普文章经行管理
  6. 店铺管理:对各个店铺信息进行管理,可以对店铺的名称、地址、介绍进行修改。

对一下管理员及用户进行用例分析:

后台管理员虽对系统的所有功能都具备操作权限,但本质上只执行与网络信息审计相关 的操作,对于不符合网络规范的相关内容进行记录和删除等操作,以保证网络信息内容 的合法性、健康性和安全性:

  1. 后台管理员
  1. 科普文章管理:修改文章,删除文章,设置文章推荐
  2. 问答管理:删除问答,设置问答推荐,设置问答显示
  3. 店铺管理:修改店铺名称,修改店铺地址,修改店铺简介,删除无效店铺
  4. 用户管理

专家用户对自己相关信息有操作权限,用来管理相关内容:

  1. 专家用户:
  1. 问题管理:修改、删除、输入问题及其回答
  2. 专家信息管理:修改专家自身信息
  3. 文章管理:修改、删除专家自己的文章

普通用户使用软件,可以实现查看文章,向专家提问,查看专家详情等操作,可对自己信息进行管理

3)普通用户:

      1.查看文章:用户可查看文章以及对文章点赞

      2.向专家提问:用户可向选定专家提问,内容包含文字、图片。

      3.查看专家详情:用户可查看专家的姓名,专业,组织等信息。

      4.用户信息管理:用户对自己信息进行修改和管理。

用例图:

3智慧农业管理系统的设计

3.1 系统的总体设计

系统结构图

智慧农业管理系统的总体设计架构,其中核心功能被分:科普文章、专家问答、店铺、用户管理。在科普文章子系统中包括用户查看模块,和管理模块,可对软件内的文章进行管理。专家问答子系统中包含用户问答模块,专家问答模块,问答管理模块,可以对软件内用户对专家的提问和专家的回答内容进行管理。店铺子系统包括店铺信息模块,可对店铺信息进行管理。

3.2 系统架构设计

本次软件开发主要采用spring框架进行软件开发,使用maven和springboot实现对jar包的管理和版本的统一;使用mybatis plus技术简化程序对数据库的操作的实现;使用swagger对软件的接口进行文档化管理;采用MVC结构实现交互,业务分离;采用vue前端框架进行前端代码工程化开发;使用gitlab对代码进行管理。

系统架构:MVC三层架构

软件模式:B/S模式

MVC,即Model模型,View模型,Controller模型

Model:承载数据,对用户提交请求进行计算的模块。分为两类,一类称为数据承载Bean,一类称为业务处理Bean。业务处理Bean指的是Service或DAO对象,用于处理用户提出的请求;数据承载Bean指的是实体类,用于用户承载业务数据,本次软件开发中,涉及到article,expert,expertArticle,shop等类,将这些类划分到model层中。

View:视图,为用户提供直观的使用界面,与用户直接进行交互,如本课设中用到的javax.swing所完成的图形化界面。本次软件开发中,视图层包括 html,js,css的代码,所以view层由vue框架开发。

Controller:控制器,用于将用户的请求转发给相应的Model进行,并计算后给予用户反馈。本次软件开发中需要对article,expert,expertArticle,shop等类进行操作,分别需要各自的controller才操作。

(这里写上项目所采用的具体的面向服务的架构,采用的框架,技术。

并采用下图的方式描述系统面向服务的设计,这里只是参考,需要根据自己的项目来画图。)

3.3  服务的设计

3.3.1在总体设计的基础上将功能或子功能映射为服务

3.3.2每个服务的操作和协作设计

3.3.3 如果采用restful风格的服务,则需要说明API的设计。参考如下。

如果采用soap的服务,则需要描述服务接口和服务实现类(@webservice标注的,需要被发布publish的,可列表说明,不是@service标注)。

3.4 各服务层次结构的设计

分层描述(controller service domain

3.4.1 科普文章

3.4.2 专家问答

3.4.3 店铺管理

3.4.4 用户管理

Admin服务定义了两个接口函数,

showAdminByPwd是通过id编号来返回数据库中相应的admin对象

showAdminByNameAndPwd是通过用户名和密码编号来返回数据库中相应的admin对象

3.5  数据库的设计(如果有,可以不用数据库)

科普文章:article

    id     bigint auto_increment comment '文章ID' primary key,

    title        varchar(100)         null comment '文章标题',

    type         varchar(50)          null comment '类别',

    cover_img    varchar(200)         null comment '封面图20*20',

    source       varchar(300)         null comment '来源',

    source_link  varchar(300)         null comment '来源链接',

    content_type tinyint(2)           null comment '内容类型: 1 图文 2 视频 ',

    content      longtext             null comment '正文',

    video_url    varchar(200)         null comment '视频文件链接',

    video_name   varchar(200)         null comment '视频文件名',

    video_desc   varchar(500)         null comment '视频描述',

    read_count   int                  null comment '阅读量',

    recommend    tinyint(2)       null comment '推荐状态: 0 未推荐 1 推荐',

    status       tinyint(2)           null comment '状态: 0 禁用 1 启用',

    publish_time datetime             null comment '发布时间',

    create_time  datetime             null comment '创建时间',

    update_time  datetime             null comment '修改时间',

    creator_id   bigint               null comment '创建人',

    updator_id   bigint               null comment '修改人',

    creator_name varchar(45)          null comment '创建人名称',

    version      varchar(45)          null comment '乐观锁版本号',

    del          tinyint(2) default 0 null comment '删除: 0 未删除 32 已删除'

  

专家问答:_expert_ask

    id     bigint auto_increment comment '问题ID'  primary key,

    org_id           bigint               null comment '提问组织ID',

    user_id          bigint               null comment '提问用户ID',

    user_name        varchar(45)          null comment '提问人名称',

    answer_user_id   bigint               null comment '回复人ID',

    answer_user_name varchar(45)          null comment '回复人名称',

    question         varchar(2000)        null comment '问题内容',

    images           varchar(2000)        null comment '图片',

    answer_content   varchar(2000)        null comment '回答内容',

    status        tinyint(2) default 0 null comment '状态: 0 待解决 1 已解决',

    pub_flag      tinyint(2) default 0 null comment '公开: 0 不公开 1 公开',

    answer_time      datetime             null comment '回答时间',

    create_time      datetime             null comment '创建时间',

    update_time      datetime             null comment '修改时间',

    creator_id       bigint               null comment '创建人',

    updator_id       bigint               null comment '修改人',

    creator_name     varchar(45)          null comment '创建人名称',

    version          varchar(45)          null comment '乐观锁版本号',

    del           tinyint(2) default 0 null comment '删除: 0 未删除 38 已删除'

专家:expert

id      bigint auto_increment comment '专家id'   primary key,

    expert_name       varchar(45) collate utf8mb4_bin  null comment '专家名称',

    profession        tinyint(2)                       null comment '专业',

    org_id            bigint                           not null comment '所属组织id',

    org               varchar(100) collate utf8mb4_bin null comment '所属组织',

    phone_number      varchar(45) collate utf8mb4_bin  null comment '联系电话',

    individual_resume varchar(300) collate utf8mb4_bin null comment '个人简介',

    image             varchar(200) collate utf8mb4_bin null comment '图片',

    phone_account     varchar(45) collate utf8mb4_bin  null comment '手机账号',

    status            tinyint(1) default 1             null comment '0禁用 1启用',

    create_time       datetime                         null comment '创建时间',

    update_time       datetime                         null comment '修改时间',

    creator_id        bigint                           null comment '创建人',

    updator_id        bigint                           null comment '修改人',

    creator_name      varchar(45) collate utf8mb4_bin  null comment '创建人名称',

    version           varchar(45) collate utf8mb4_bin  null comment '乐观锁版本号',

    del               tinyint(2) default 0             null comment '删除: 0 未删除 1 已删除'

4 智慧农业管理系统的实现

4.1项目结构及配置

4.1.1项目结构

  1. controller控制器:用于控制页面的跳转,调用业务逻辑层
  2. 编写service接口和接口的实现类,对数据访问层进行增删改查操作的组装,接收表示层的请求调用。
  3. 通过Spring 基于jpa标准操作数据的模块,无需写实现类,不用写sql语句直接查询数据库中的数据,实现对数据库的增删改查。
  4. 使用Springboot框架,使用yml文件对各类配置进行管理。

4.1.2项目配置

设置dns

vim /etc/resolv.conf

# 注释原有的,改成公共的dns

nameserver 223.5.5.5

nameserver 8.8.8.8

# 下面是为了解决重启服务器dns还原的问题

cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-eth0.bak

cat >> /etc/sysconfig/network-scripts/ifcfg-eth0 << EOF

DNS1=114.114.114.114

DNS2=8.8.8.8

EOF

设置主机名

hostnamectl set-hostname {host名}

添加数据盘

fdisk -l #查看数据盘名

fdisk /dev/vdb

(m,n,p,回车,回车,回车,wq)

partprobe

#格式化数据盘

mkfs.xfs -f /dev/vdb

# 创建挂载目录

mkdir -p /data

# 挂载磁盘

mount /dev/vdb /data

df -T -h # 查看磁盘时候挂载成功

echo '/dev/vdb /data xfs defaults 0 0' >>/etc/fstab

# 重启测试

reboot

安装nginx

在线安装nginx

配置yum

vim /etc/yum.repos.d/nginx.repo

[nginx-stable]

name=nginx stable repo

baseurl=http://nginx.org/packages/centos/$releasever/$basearch/

gpgcheck=1

enabled=1

gpgkey=https://nginx.org/keys/nginx_signing.key

module_hotfixes=true

[nginx-mainline]

name=nginx mainline repobaseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/

gpgcheck=1

enabled=0

gpgkey=https://nginx.org/keys/nginx_signing.key

module_hotfixes=true

安装nginx

yum install nginx -y

启动设置开机自启

# systemctl start nginx

# systemctl enable nginx

编译安装nginx

环境准备:先安装准备环境

#yum install gcc gcc-c++ automake pcre pcre-devel zlip zlib-devel openssl openssl-devel

下载安装nginx

官方下载地址http://nginx.org/en/download.htm

# cd /usr/local/src

# wget http://nginx.org/download/nginx-1.22.2.tar.gz

# tar axf nginx-1.22.2.tar.gz

编译安装

# cd nginx-1.20.2

# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-stream

# make && make install

nginx开机自启

配置开机自启动

# vi /lib/systemd/system/nginx.service

[Unit] Description=nginx service

After=network.target

[Service]

Type=forking

ExecStart=/usr/local/nginx/sbin/nginx

ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s quit

PrivateTmp=true

[Install]

WantedBy=multi-user.target

# 启动设置开机自启

# systemctl start nginx

# systemctl enable nginx

数据库配置

datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
#    url: jdbc:mysql://www.bunint.com:3306/ruian_zn_test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8&sslMode=disabled&nullCatalogMeansCurrent=true
#    username: ruian_zn_test
#    password: ruian_zn_test
    url: jdbc:mysql://rm-bp1f4f79rn235buk9mo.mysql.rds.aliyuncs.com:31525/ruian_zn_test?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8&sslMode=disabled&nullCatalogMeansCurrent=true
    username: nhsztest
    password: nhsz@testZNF
#    driverClassName: dm.jdbc.driver.DmDriver
#    url: jdbc:dm://120.26.98.90:52360/RUIAN_ZN_TEST?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
#    username: SYSDBA
#    password: SYSDBA

Redis配置

redis:
  database: 5
  host: 49.233.0.170
  port: 6379
  timeout: 10000
  password: 123456

4.2 服务实现的关键代码

4.1内容管理:专家问答(网页端)

    4.1.1主要功能

       1)专家问答数据分页查询

        进入内容管理的专家问答详情界面,界面通过表格形式,分页显示数据库内所有的专家问答记录。

    2)专家问答数据多条件筛选查询

        在文本框中输入查询条件,点击查询,界面对数据进行筛选,筛选结果通过表格分页显示;输入筛选条件后,点击重置按钮,输入的筛选条件清空。

    3)问题解决操作(仅专家可操作)

        专家点击解决按钮后,界面弹出解决问题窗口,窗口显示用户提问的问题内容和问题图片,专家可在文本框中输入问题解决内容,点击确定后,保存。

    4)问答公开操作

        点击空开按钮,此条问答数据将可公开,表格中词条数据的显示状态改编为公开,按钮变为取消公开,可公开的问答可在APP端显示。

    5)取消公开

        与公开操作相反

    6)查看问答详情操作

        点击查看详情按钮,界面弹出详情窗口,显示问答内容。

       4.1.2程序实现截图

1)专家问答数据分页查询

问答数据通过表格形式展示:

图形用户界面, 应用程序, 表格  描述已自动生成

图5-1专家问答分页查询

分页查询: 

图形用户界面, 应用程序  描述已自动生成

图5-2分页查询

    2)专家问答数据多条件筛选查询

图形用户界面  中度可信度描述已自动生成

图5-3专家问答条件筛选

    3)问题解决操作(仅专家可操作)

    点击解决问题,弹出解决问题界面:

图形用户界面, 应用程序  描述已自动生成

图5-4解决问题界面

    解决问题界面输入内容后点击确定,数据保存,点击查看详情按钮,查看输入的内容:

图形用户界面, 应用程序, Teams  描述已自动生成

图5-5查看解决问题后的数据

    4)问答公开操作

    点击公开按钮:

表格  描述已自动生成

图5-6问答公开操作

    5)取消公开操作

    与公开操作相反:略

6)查看问答详情操作

    点击查看详情按钮,弹出问答详情界面

图形用户界面, 应用程序, Teams  描述已自动生成

图5-7查看详情

       4.1.3主要实现代码及注释

Controller层:

@Api(tags = "专家问答")

@RestController

@RequestMapping("/web/store/expertAsk")

public class ExpertAskController extends BaseController {

    @Autowired

    private ExpertAskService expertAskService;

    @Autowired

    private MessageApiClient messageApiClient;

    /**

     * 专家问答分页查询

     */

    @ApiOperation("专家问答分页查询")

    @GetMapping("/page/list")

    public Result<Page<ExpertAskVO>> queryByPage(ExpertAskQuery query){

        // 判断身份,如果是专家则只能看到自己的

        IPage<ExpertAsk> page = expertAskService.queryByPage(query);

        List<ExpertAskVO> list = BeanUtil.copyToList(page.getRecords(), ExpertAskVO.class);

        Page<ExpertAskVO> pageVO = new Page<>();

        pageVO.setPages(query.getPageNum());

        pageVO.setSize(query.getPageSize());

        pageVO.setTotal(page.getTotal());

        pageVO.setRecords(list);

        return new Result().ok(pageVO);

    }

    /**

     * 查看专家问答详情

     */

    @GetMapping(value = "/{id}")

    @ApiOperation("查看专家问答详情")

    public Result<ExpertAskDetailVO> queryById(@ApiParam("专家问答ID") @PathVariable Long id) {

       ExpertAsk expertAsk = expertAskService.getById(id);

        ExpertAskDetailVO expertAskVO = BeanUtil.copyProperties(expertAsk, ExpertAskDetailVO.class);

       return new Result().ok(expertAskVO);

    }

    /**

     * 解决

     */

    @PostMapping(value = "/resolve")

    @ApiOperation("解决")

    public Result<ExpertAskVO> resolve(@RequestBody @Valid ExpertAskDTO expertAskDTO) {

        ExpertAsk expertAsk = BeanUtil.copyProperties(expertAskDTO, ExpertAsk.class);

        expertAsk.setStatus(1);

        expertAsk.setAnswerTime(DateUtils.getNowDate());

        expertAsk.setUpdatorId(getLoginUserId());

        expertAsk.setUpdateTime(LocalDateTime.now());

        boolean success = expertAskService.updateExpertAsk(expertAsk);

        if(success){

            messageApiClient.sendMessage(expertAsk.getUserId(),"专家回复通知","您的提问已回复,回复内容:"+expertAskDTO.getAnswerContent());

        }

        return new Result().ok(success);

    }

    /**

     * 新增专家问答

     */

    @PostMapping("

Server层:

@Service

public class ExpertAskServiceImpl extends ServiceImpl<ExpertAskDao, ExpertAsk> implements ExpertAskService {

    @Autowired

    private ExpertAskDao expertAskDao;

    @Autowired

    private ExpertDao expertManagementDao;

    public IPage<ExpertAsk> queryByPage(ExpertAskQuery query) {

        LambdaQueryWrapper<ExpertAsk> wrapper = Wrappers.lambdaQuery();

        if (expertManagementDao.selectById(query.getId()) != null) {  //此用户是专家

            wrapper.eq(ExpertAsk::getAnswerUserId, query.getId());

        }

        wrapper.like(query.getQuestion() != null, ExpertAsk::getQuestion, query.getQuestion());

        wrapper.like(query.getUserName() != null, ExpertAsk::getUserName, query.getUserName());

        wrapper.like(query.getAnswerUserName() != null, ExpertAsk::getAnswerUserName, query.getAnswerUserName());

        wrapper.eq(query.getStatus() != null, ExpertAsk::getStatus, query.getStatus());

        wrapper.eq(query.getPubFlag() != null, ExpertAsk::getPubFlag, query.getPubFlag());

        wrapper.ge(query.getStartTime()!=null,ExpertAsk::getCreateTime,query.getStartTime());

        wrapper.le(query.getEndTime()!=null,ExpertAsk::getCreateTime,query.getEndTime());

        wrapper.eq(ExpertAsk::getDel, 0);

        wrapper.orderByDesc(ExpertAsk::getCreateTime);

        return expertAskDao.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper);

    }

    @Override

    public IPage<ExpertAsk> queryByPage(AppExpertAskQuery query) {

        LambdaQueryWrapper<ExpertAsk> wrapper = Wrappers.lambdaQuery();

        if (query.getUserId() == null) {   //用户id为空,说明展示专家问答或者ta的问答

            wrapper.eq(query.getAnswerUserId() != null, ExpertAsk::getAnswerUserId, query.getAnswerUserId());

            wrapper.eq(ExpertAsk::getPubFlag, 1);

            wrapper.eq(ExpertAsk::getStatus, 1);

        } else {  //

            wrapper.eq(ExpertAsk::getUserId, query.getUserId());

        }

        wrapper.eq(ExpertAsk::getDel, 0);

        wrapper.orderByDesc(ExpertAsk::getCreateTime);

        return expertAskDao.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper);

    }

    @Override

    public boolean insertExpertAsk(ExpertAsk expertAsk) {

        int ct = expertAskDao.insert(expertAsk);

        return ct > 0;

    }

    @Override

    public boolean updateExpertAsk(ExpertAsk expertAsk) {

        int ct = expertAskDao.updateById(expertAsk);

        return ct > 0;

    }

    @Override

    public int getConsultationCount(Long id) {

        LambdaQueryWrapper<ExpertAsk> wrapper = Wrappers.lambdaQuery();

        wrapper.eq(ExpertAsk::getAnswerUserId, id);

        return expertAskDao.selectCount(wrapper);

    }

    @Override

    public int getReplyCount(Long id) {

        LambdaQueryWrapper<ExpertAsk> wrapper = Wrappers.lambdaQuery();

        wrapper.eq(ExpertAsk::getAnswerUserId, id);

        wrapper.isNotNull(ExpertAsk::getAnswerContent);

        return expertAskDao.selectCount(wrapper);

    }

    4.1.4对实现中所用方法和重要算法等的说明

1)分页查询接口。判断用户id是否为空,若为空,说明此接口为展示专家问答或者TA的回答,则将筛选条件设置为已公开,已解决;若id不为空,说明此接口用于展示当前登录用户的问答,则筛选条件为用户id。

图形用户界面, 文本, 应用程序  描述已自动生成

4.2内容管理:科普文章(网页端)

4.2.1主要功能

1)科普文章数据分页查询

       进入科普文章界面,科普文章数据通过表格的形式分页查询,显示喜好,标题,分类等信息

2)科普文章数据筛选查询

       在文本框中输入查询条件,点击查询按钮,系统筛选符合条件的数据,将筛选后的数据以表格的形式分页查询。点击重置,筛选条件失效。

3)新增文章

点击新增按钮,弹出新增界面,用户输入新增文章的信息,点击保存。

4)修改科普文章

       点击修改按钮,弹出文章修改界面,输入修改的内容,点击保存按钮,修改后的数据保存,点击取消,返回主界面。

5)禁用/启用科普文章

       点击禁用/启用按钮,修改文章的启用状态,启用的文章将在APP端的庄稼医院中显示。

6)推荐/取消推荐科普文章

       点击推荐,取消推荐按钮,修改文章的推荐状态,推荐的文章将在APP端主页显示。

       4.2.2程序实现截图

       1)科普文章数据分页查询

       进入科普文章界面,科普文章数据通过表格显示:

图形用户界面, 应用程序  描述已自动生成

图5-8科普文章分页查询

       2)科普文章数据筛选查询

       在文本框中输入筛选条件,系统使用表格形式展示筛选后的数据

图形用户界面, 应用程序  描述已自动生成

图5-9 科普文章筛选

       3)新增文章

图形用户界面, 应用程序  描述已自动生成

图5-10新增科普文章

当必填项用户没有输入且点击保存时,界面提醒用户

图形用户界面, 应用程序  描述已自动生成

图5-11新增科普文章(未填)

4)修改科普文章

点击修改按钮,修改界面弹出,显示被修改的文章原有数据。

图形用户界面, 应用程序  描述已自动生成

图5-11修改科普文章

       5)禁用/启用科普文章          

图5-12设置启用

图5-13设置禁用

       6)推荐/取消推荐科普文章

图5-14设置推荐

图5-15求取消推荐

       4.2.3主要实现代码及注释

Controller层:

@Api(tags = "科普文章")

@RestController

@RequestMapping("/web/store/article")

public class ArticleController extends BaseController {

    @Autowired

    private ArticleService articleService;

    /**

     * 科普文章分页查询

     */

    @ApiOperation("科普文章分页查询")

    @GetMapping("/page/list")

    public Result<Page<ArticleListVO>> queryByPage(ArticleQuery query) {

        IPage<Article> page = articleService.queryByPage(query);

        List<ArticleListVO> list = BeanUtil.copyToList(page.getRecords(), ArticleListVO.class);

        Page<ArticleListVO> pageVO = new Page<>();

        pageVO.setPages(query.getPageNum());

        pageVO.setSize(query.getPageSize());

        pageVO.setTotal(page.getTotal());

        pageVO.setRecords(list);

        return new Result().ok(pageVO);

    }

    /**

     * 查看科普文章详情

     */

    @GetMapping(value = "/{id}")

    @ApiOperation("查看科普文章详情")

    public Result<ArticleVO> queryById(@ApiParam("科普文章ID") @PathVariable Long id) {

        Article article = articleService.getById(id);

        ArticleVO articleVO = BeanUtil.copyProperties(article, ArticleVO.class);

        return new Result().ok(articleVO);

    }

    /**

     * 新增科普文章

     */

    @PostMapping("/insert")

    @ApiOperation("新增科普文章")

    public Result insert(@RequestBody @Valid Article article) {

        article.setCreatorInfo(getLoginUserId(),getLoginUserName());

        article.setReadCount(1L);

        article.setStatus(1);

        article.setRecommend(0);

        article.setPublishTime(LocalDateTime.now());

        boolean success = articleService.insertArticle(article);

        return new Result().ok(success);

    }

    /**

     * 修改科普文章

     */

    @PostMapping("/update")

    @ApiOperation("修改科普文章")

    public Result update(@RequestBody @Valid Article article) {

        article.setUpdatorId(getLoginUserId());

        article.setUpdateTime(LocalDateTime.now());

        boolean success = articleService.updateArticle(article);

        return new Result().ok(success);

    }

    /**

     * 禁用/启用

     */

    @PostMapping("/status")

    @ApiOperation("禁用/启用")

    public Result updateStatus(@ApiParam(value = "文章ID", required = true) @RequestParam Long id,

                               @ApiParam(value = "状态:0=禁用 1=启用", required = true) @RequestParam Integer status) {

        Article article = new Article();

        article.setId(id);

        article.setStatus(status);

        article.setUpdatorId(getLoginUserId());

        article.setUpdateTime(LocalDateTime.now());

        if (article.getStatus() != null && article.getStatus() == Constants.INT_ONE) {

            article.setPublishTime(LocalDateTime.now());

        }

        return new Result().ok(this.articleService.updateById(article));

    }

    /**

     * 设置/取消推荐

     */

    @PostMapping("/recommend")

    @ApiOperation("设置/取消推荐")

    public Result updateRecommend(@ApiParam(value = "文章ID", required = true) @RequestParam Long id,

                                  @ApiParam(value = "文章推荐:0=未推荐 1=推荐", required = true) @RequestParam Integer recommend) {

        Article article = new Article();

        article.setId(id);

        article.setRecommend(recommend);

        article.setUpdatorId(getLoginUserId());

        article.setUpdateTime(LocalDateTime.now());

        return new Result().ok(this.articleService.updateById(article));

    }

    /**

     * 批量删除科普文章

     */

    @PostMapping("/delete")

    @ApiOperation("批量删除科普文章")

    public Result delete(@ApiParam("科普文章ID列表") @RequestParam List<Long> ids) {

        boolean success = articleService.removeByIds(ids);

        return new Result().ok(success);

    }

    /**

     * 删除科普文章

     */

    @PostMapping("/deleteById/{id}")

    @ApiOperation("删除科普文章")

    public Result deleteById(@ApiParam("科普文章ID") @PathVariable Long id) {

        Article article = new Article();

        article.setId(id);

        article.setUpdatorId(getLoginUserId());

        article.setUpdateTime(LocalDateTime.now());

        article.setDel(1);

        boolean success = articleService.updateById(article);

        return new Result().ok(success);

    }

}

Server层:

@Service

public class ArticleServiceImpl extends ServiceImpl<ArticleDao, Article> implements ArticleService {

    private static final long MAX_POST_SIZE = 5 * 1024l * 1024l;

    @Autowired

    private ArticleDao articleDao;

    @Autowired

    OSSHolder ossHolder;

    public IPage<Article> queryByPage(ArticleQuery query) {

        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();

        wrapper.like(query.getTitle() != null, Article::getTitle, query.getTitle());

        wrapper.eq(StrUtil.isNotBlank(query.getType()), Article::getType, query.getType());

        wrapper.eq(query.getRecommend() != null, Article::getRecommend, query.getRecommend());

        wrapper.eq(query.getStatus() != null, Article::getStatus, query.getStatus());

        wrapper.ge(query.getStartTime() != null, Article::getCreateTime, query.getStartTime());

        wrapper.le(query.getEndTime() != null, Article::getCreateTime, query.getEndTime());

        wrapper.eq(Article::getDel, 0);

        wrapper.orderByDesc(Article::getCreateTime);

        return articleDao.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper);

    }

    @Override

    public IPage<Article> queryByPage(AppArticleQuery query) {

        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();

        wrapper.eq(ObjectUtil.isNotEmpty(query.getType()), Article::getType, query.getType());

        wrapper.eq(Article::getStatus, Constants.INT_ONE);

        wrapper.orderByDesc(Article::getCreateTime);

        wrapper.orderByDesc(Article::getPublishTime);

        return articleDao.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper);

    }

    @Override

    public IPage<Article> queryByPageMain(AppArticleQuery query) {

        LambdaQueryWrapper<Article> wrapper = Wrappers.lambdaQuery();

        wrapper.eq(ObjectUtil.isNotEmpty(query.getType()), Article::getType, query.getType());

        wrapper.eq(Article::getStatus, Constants.INT_ONE);

        wrapper.eq(Article::getRecommend, Constants.INT_ONE);

        wrapper.orderByDesc(Article::getCreateTime);

        wrapper.orderByDesc(Article::getPublishTime);

        return articleDao.selectPage(new Page(query.getPageNum(), query.getPageSize()), wrapper);

    }

    @Override

    public boolean insertArticle(Article article) {

        ArticleDTO articleDTO = BeanUtil.copyProperties(article, ArticleDTO.class);

        validateArticle(articleDTO);

        int ct = articleDao.insert(article);

        return ct > 0;

    }

    @Override

    public boolean updateArticle(Article article) {

        ArticleDTO articleDTO = BeanUtil.copyProperties(article, ArticleDTO.class);

        validateArticle(articleDTO);

        int ct = articleDao.updateById(article);

        return ct > 0;

    }

    private void validateArticle(ArticleDTO articleDTO) {

        Integer type = articleDTO.getContentType();

        if (ArticleEnum.ArticleType.IMAGE_TEXT.getCode().equals(type)) {

            validateByImage(articleDTO);

        } else if (ArticleEnum.ArticleType.VIDEO.getCode().equals(type)) {

            validateByVideo(articleDTO);

        }

    }

    /**

     * 图文校验

     *

     * @param articleDTO

     */

    public void validateByImage(ArticleDTO articleDTO) {

        ValidatorUtils.validate(articleDTO, Default.class, ArticleDTO.GroupImage.class);

    }

    /**

     * 视频校验

     */

    public void validateByVideo(ArticleDTO articleDTO) {

        ValidatorUtils.validate(articleDTO, Default.class, ArticleDTO.GroupVideo.class);

    }

}  

4.2.4对实现中所用方法和重要算法等的说明

1)分类校验。当用户选择文章类型为文本时,采用文本校验;当用户选择文章类型为视频时,采用视频校验。文本校验时,需要判断文章标题是否为空,文章正文内容是否为空,文章正文内容字数是否超过2000字;视频校验时,需要判断视频文件连接是否为空,视频标题是否超过20字,视频文件是否为空。

4.4庄稼医院(APP端)

4.4.1主要功能

       1)文章政策分页查询

       点击主页庄稼医院按钮,进入文章政策界面,分页查询已公开的文章。

       2)文章分类查询

       点击窗口上方分类栏,按照文章类别分类查询。

       3)查看文章详情

       点击文章,跳转至文章内容界面。

       4.4.2程序实现截图

1)文章政策分页查询

       点击主页庄稼医院按钮,进入文章政策界面,分页查询已公开的文章。

图形用户界面, 应用程序  描述已自动生成

图5-21文章政策

       2)文章分类查询

       点击窗口上方分类栏,按照文章类别分类查询。

图形用户界面, 应用程序  描述已自动生成

图5-22文章政策分类查询

       3)查看文章详情

       点击文章,跳转至文章内容界面。

手机屏幕截图  中度可信度描述已自动生成

图5-23文章详情

       4.4.3主要实现代码及注释

Controller

@Api(tags = "文章政策")

@RestController

@RequestMapping("/app/store/article")

public class AppArticleController extends BaseController {

    @Autowired

    private ArticleService articleService;

    /**

     * 科普文章分页查询

     */

    @ApiOperation("科普文章分页查询")

    @GetMapping("/page/list")

    public Result<Page<ArticleVO>> queryByPage(AppArticleQuery query) {

        IPage<Article> page = articleService.queryByPage(query);

        List<ArticleVO> list = BeanUtil.copyToList(page.getRecords(), ArticleVO.class);

        Page<ArticleVO> pageVO = new Page<>();

        pageVO.setPages(query.getPageNum());

        pageVO.setSize(query.getPageSize());

        pageVO.setTotal(page.getTotal());

        pageVO.setRecords(list);

        return new Result().ok(pageVO);

    }

    /**

     * 科普文章分页查询(主页)

     */

    @ApiOperation("科普文章分页查询(主页)")

    @GetMapping("/page/main/list")

    public Result<Page<ArticleVO>> queryByPageMain(AppArticleQuery query) {

        IPage<Article> page = articleService.queryByPageMain(query);

        List<ArticleVO> list = BeanUtil.copyToList(page.getRecords(), ArticleVO.class);

        Page<ArticleVO> pageVO = new Page<>();

        pageVO.setPages(query.getPageNum());

        pageVO.setSize(query.getPageSize());

        pageVO.setTotal(page.getTotal());

        pageVO.setRecords(list);

        return new Result().ok(pageVO);

    }

    /**

     * 查看科普文章详情

     */

    @GetMapping(value = "/{id}")

    @ApiOperation("查看科普文章详情")

    public Result<ArticleVO> queryById(@ApiParam("科普文章ID") @PathVariable Long id) {

        Article article = articleService.getById(id);

        ArticleVO articleVO = BeanUtil.copyProperties(article, ArticleVO.class);

        article.setReadCount(article.getReadCount()+1L);

        articleService.updateById(article);

        return new Result().ok(articleVO);

    }

}

    4.4.4对实现中所用方法和重要算法等的说明

1)APP端专家列表接口,通过expertService.queryAll查询数据库中所有专家记录,存放在List<AppExpertListVO> expertList中,使用dictValueService.queryProfession()从数据字典中获取专家专业的字典值,采用数据流的方式,拼接专家和专家专业。

图形用户界面, 文本, 应用程序  描述已自动生成

4.5店铺详情(APP端)

4.5.1主要功能

1)店铺详情,显示当前店铺的店铺名称,联系人,联系电话,地址等信息。

       4.5.2程序实现截图

图形用户界面, 应用程序  描述已自动生成

5-24店铺详情

       4.5.3主要实现代码及注释

Controller

@Api(tags = "01.店铺信息")

@RestController

@RequestMapping("/web/store/shop")

public class ShopController {

    @Autowired

    private ShopService shopService;

    /**

     * 店铺信息分页查询

     */

    @ApiOperation("分页查询店铺列表")

    @GetMapping("/page/list")

    public Result<Page<ShopVO>> queryByPage(ShopQuery query){

        IPage<Shop> page = shopService.queryByPage(query);

        List<ShopVO> list = BeanUtil.copyToList(page.getRecords(),ShopVO.class);

        Page<ShopVO> pageVO = new Page<>();

        pageVO.setPages(query.getPageNum());

        pageVO.setSize(query.getPageSize());

        pageVO.setTotal(page.getTotal());

        pageVO.setRecords(list);

        return new Result().ok(pageVO);

    }

}

Server

@Service

public class ShopServiceImpl extends ServiceImpl<ShopDao, Shop> implements ShopService

{

    @Autowired

    private ShopDao shopDao;

    @Autowired

    private OrganizationService organizationService;

    public IPage<Shop> queryByPage(ShopQuery query){

        LambdaQueryWrapper<Shop> wrapper = Wrappers.lambdaQuery();

        wrapper.like(StrUtil.isNotBlank(query.getKeyword()),Shop::getShopName, query.getKeyword());

        wrapper.orderByDesc(Shop::getCreateTime);

        return shopDao.selectPage(new Page(query.getPageNum(),query.getPageSize()),wrapper);

    }

    @Override

    public List<Shop> queryShopList(List<Long> shopIds) {

        if(CollectionUtil.isEmpty(shopIds)){

            return Lists.newArrayList();

        }

        return shopDao.selectList(Wrappers.<Shop>lambdaQuery()

                        .eq(Shop::getDel, DelFlagEnum.NOT_DELETED.getFlag())

                        .in(Shop::getId,shopIds));

    }

    @Override

    public Map<Long, Shop> queryShopMap(List<Long> shopIds) {

        List<Shop> list = queryShopList(shopIds);

        if(CollectionUtil.isEmpty(list)){

            return MapUtil.newHashMap();

        }

        return list.stream().collect(Collectors.toMap(Shop::getId, Function.identity()));

    }

    @Override

    public Shop getShopByOrgId(Long orgId) {

        return shopDao.selectOne(Wrappers.<Shop>lambdaQuery()

                .eq(Shop::getOrgId,orgId).last(" limit 1"));

    }

    @Override

    public boolean insertShop(Shop shop) {

        validateShop(shop);

        int ct = shopDao.insert(shop);

        return ct>0;

    }

    @Override

    public boolean updateShop(Shop shop) {

        validateShop(shop);

        int ct = shopDao.updateById(shop);

        return ct>0;

    }

    /**

     * 只有服务商可以注册店铺

     */

    private void validateShop(Shop shop) {

        Long orgId = shop.getOrgId();

        Organization org = organizationService.getById(orgId);

        Integer orgType = Optional.ofNullable(org)

                .map(Organization::getOrgType)

                .orElse(null);

        if(!OrganizationEnum.OrgType.SERVICE_PROVIDER.getCode().equals(orgType)) {

            // 如果当前登录不是服务商

            throw new BusinessException("更新店铺失败,请先切换为服务商身份");

        }

    }

}

总结

通过这次SOA和Web service技术课程设计,我锻炼了Navicat,idea等软件的熟练使用,掌握创建一个基于SOAP的Web服务的基本流程,掌握使用spring boot创建RESTful风格的服务端,并创建客户端程序,以及掌握使用Spring Cloud + Spring Boot构建微服务,建立分布式注册中心,进行分布式通信和设置分布式断路器。将课上所学知识与现实中的实际问题联系在一起,能够使问题简单化,通过MVC三层结构使用户能直接更改数据库的数据。我的课程设计是智慧农业管理系统,目的是使农户可以方便的管理,销售农产品,方便农户及时了解农业新闻,加强各地专家与农户交流联系,发展智慧农业。

在本次课设中依然存在不足的地方, 使用vue进行前端界面开发时不熟练;在数据库管理方面,未采用索引等方法优化数据库查询效率;后端采用springcloud等分布式开发方式时,使用各类微服务、分布式技术没有十分熟练,希望在之后的学习中,继续提高自己的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值