分布式项目搭建
页面原型展示 :
技术选型 :
前端技术选型 :
后端技术选型 (有些可能并没有用到):
项目开发环境 :
开发工具:
后端:IDEA 2019
前端:VS code
数据库客户端工具:SQLYog
开发环境:
JDK 11
Maven 3.6.3
MySQL 5.7
Zookeeper 3.6.0
Dubbo 2.5.7
Redis 5.0.4
开发后端服务接口 :
我们采用前后端分离的开发模式,先开发后端服务接口,测试成功,再开发前端vue界面,最后进行前后端联调,项目上线
项目结构与命名 :
单一架构:
分布式架构:
后端项目架构,我们采用dubbo的生产者和消费者的理论
创建服务提供方和服务消费方两个工程,通过maven聚合工程来搭建,模块划分如下:
服务提供
lagou-edu-parent:pom聚合父工程,统一依赖设置
lagou-edu-entity:jar工程,封装实体类
lagou-edu-dao:jar工程,封装与数据库打交道的部分
lagou-edu-service:web工程,暴露服务的接口和实现
服务消费
lagou-edu-web:web工程,接收前端工程发来的请求,远程调用服务并消费
URL命名:
查询:http://localhost:8002/course/getList — get开头
保存:http://localhost:8002/course/saveXx — save开头
更新:http://localhost:8002/course/updateXx — update开头
接口响应格式 :
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ResponseDTO < T > implements Serializable {
private static final long serialVersionUID = 1L ;
private int state;
private String message;
private T content;
}
pom.xml:
< properties>
< spring.version> 5.0.6.RELEASE</ spring.version>
</ properties>
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-beans</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-webmvc</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-jdbc</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-aspects</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-test</ artifactId>
< version> ${spring.version}</ version>
< scope> test</ scope>
</ dependency>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.2.8</ version>
</ dependency>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis-spring</ artifactId>
< version> 1.3.2</ version>
</ dependency>
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> druid</ artifactId>
< version> 1.0.9</ version>
</ dependency>
< dependency>
< groupId> mysql</ groupId>
< artifactId> mysql-connector-java</ artifactId>
< version> 5.1.32</ version>
</ dependency>
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> dubbo</ artifactId>
< version> 2.5.7</ version>
</ dependency>
< dependency>
< groupId> org.apache.zookeeper</ groupId>
< artifactId> zookeeper</ artifactId>
< version> 3.4.6</ version>
</ dependency>
< dependency>
< groupId> com.github.sgroschupf</ groupId>
< artifactId> zkclient</ artifactId>
< version> 0.1</ version>
</ dependency>
< dependency>
< groupId> javassist</ groupId>
< artifactId> javassist</ artifactId>
< version> 3.11.0.GA</ version>
</ dependency>
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> fastjson</ artifactId>
< version> 1.2.47</ version>
</ dependency>
< dependency>
< groupId> junit</ groupId>
< artifactId> junit</ artifactId>
< version> 4.12</ version>
< scope> test</ scope>
</ dependency>
< dependency>
< groupId> org.springframework.data</ groupId>
< artifactId> spring-data-redis</ artifactId>
< version> 2.3.2.RELEASE</ version>
</ dependency>
< dependency>
< groupId> redis.clients</ groupId>
< artifactId> jedis</ artifactId>
< version> 3.1.0</ version>
</ dependency>
< dependency>
< groupId> com.fasterxml.jackson.core</ groupId>
< artifactId> jackson-databind</ artifactId>
< version> 2.9.8</ version>
</ dependency>
</ dependencies>
初始化数据库:
对应的数据库设计文档和代码地址如下:
链接:https://pan.baidu.com/s/14kHif51YkKXDgsyUBTOs8A
提取码:alsk
我们idea实际上也可以操作数据库,而不用使得我们进行来回切换
如图:
点击+号,如下:
出现如下图(默认指向edu,可以切换):
注意:一般需要数据库的驱动(下载给他的,并不是项目的)
他会给你提示,你点击下载即可(好像与导入无关,可能与导入是操作项目的原因吧)
输入对应的mysql地址(以后会说明公用地址的操作,现在我们只操作专用地址,也基本就是192.168开头的地址),并输入密码
点击确定(ok和Apply)都可
然后点击如下:
这下我们就不用多次的切换窗口了
我们也可以写sql语句:
点击如下:
打开默认的sql编写窗口
接下来我们就可以编写语句了,比如(这里指向的是edu,所以操作的是edu数据库的表,在不填写数据库名的情况下,一般默认选择数据库第一个表):
点击运行,那么下面就会出现对应的表数据了
用户模块:
实体类的编写没有任意技术含量,而且还浪费时间,传说中的"老牛活"
使用一个插件可以快速生成 entity,dao,service,mapper等文件
生成"老牛活"代码的解决方案有很多种:企业中比较常见的还有"mybatis的逆向工程(可以自己学习)"
下面使用我给出的方式,先安装插件(若没有出现,则点击对应的提示,在市场搜索,或者点击上面的Marketplace)
安装完后,点击确认(默认给你勾选,最好等待操作完,然后重启,防止一些问题)
其中Easy code安装完成后(对应的Lombok需要和后面的依赖一起操作,才可使得注解起作用)
然后可以在如下图所示,看到对应选项了(右键一个表)
代表安装完成
接下来操作生成代码(操作user表):
一般都选择取消(使得他自动添加,自己添加也可)
点击ok(其对应的项目,一般默认选择最后操作的项目,虽然修改后也可能是),然后一直点击yes,那么就会出现如下
如果提示报错,可以重启idea重新加载,来防止出现问题(大概是没有加载好):
都帮你根据表的字段创建好了对应的类,一般都会指定service层
但是并不是完美的生成,可能需要自己去检查一下,看看有没有错误(比如,导入包的错误等等)
至此,代码生成完毕(记得移动对应的Dao代码以及xml文件和实体类代码到对应的项目里面)
移动后,记得删掉原来的代码,也记得再次检查包的导入
主要的错误,基本只要是包的地方,都会不对,因为我们的目录是各不相同的,而他基本只有一个形式
至此,我们选择父项目进行编译,若成功,那么代码生成操作完成,基本没有问题
注意:生成的代码,实际上我们也可以不使用,因为他只是一个模板而已
这里只是给出如何生成的操作方式,并不会完全操作他生成的代码
用户登录和注册:
lagou-edu-entity项目:
lombok小辣椒,使用注解取代原来冗余的get和set,空构造,全参数构造
< dependency>
< groupId> org.projectlombok</ groupId>
< artifactId> lombok</ artifactId>
< version> 1.18.12</ version>
< scope> provided</ scope>
</ dependency>
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. io. Serializable ;
import java. util. Date ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User implements Serializable {
private static final long serialVersionUID = 606292390505661237L ;
private Integer id;
private String name;
private String portrait;
private String phone;
private String password;
private String regIp;
private String accountNonExpired;
private String credentialsNonExpired;
private String accountNonLocked;
private String status;
private String isDel;
private Date createTime;
private Date updateTime;
}
lagou-edu-dao项目:
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<! DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd" >
< configuration>
< settings>
< setting name = " logImpl" value = " STDOUT_LOGGING" />
</ settings>
</ configuration>
spring-dao.xml:
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns: tx= " http://www.springframework.org/schema/tx"
xmlns: context= " http://www.springframework.org/schema/context"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" >
< context: component-scan base-package = " com.lagou" />
< bean id = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " url" value = " jdbc:mysql://192.168.164.128:3306/edu?
serverTimezone=GMT& characterEncoding=utf8" />
< property name = " username" value = " root" />
< property name = " password" value = " QiDian@666" />
< property name = " maxActive" value = " 10" />
< property name = " minIdle" value = " 5" />
</ bean>
< bean id = " sqlSessionFactory"
class = " org.mybatis.spring.SqlSessionFactoryBean" >
< property name = " dataSource" ref = " dataSource" />
< property name = " configLocation" value = " classpath:mybatis/mybatis-config.xml" />
</ bean>
< bean id = " transactionManager"
class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " dataSource" />
</ bean>
< tx: annotation-driven/>
< bean class = " org.mybatis.spring.mapper.MapperScannerConfigurer" >
< property name = " basePackage" value = " com.lagou.dao" />
</ bean>
</ beans>
对应生成的UserDao.xml进行修改,写成如下(多余的删除):
<?xml version="1.0" encoding="UTF-8"?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-
mapper.dtd" >
< mapper namespace = " com.lagou.dao.UserDao" >
< resultMap type = " com.lagou.entity.User" id = " UserMap" >
< result property = " id" column = " id" jdbcType = " INTEGER" />
< result property = " name" column = " name" jdbcType = " VARCHAR" />
< result property = " portrait" column = " portrait" jdbcType = " VARCHAR" />
< result property = " phone" column = " phone" jdbcType = " VARCHAR" />
< result property = " password" column = " password" jdbcType = " VARCHAR" />
< result property = " regIp" column = " reg_ip" jdbcType = " VARCHAR" />
< result property = " accountNonExpired" column = " account_non_expired" jdbcType = " VARCHAR" />
< result property = " credentialsNonExpired" column = " credentials_non_expired"
jdbcType = " VARCHAR" />
< result property = " accountNonLocked" column = " account_non_locked" jdbcType = " VARCHAR" />
< result property = " status" column = " status" jdbcType = " VARCHAR" />
< result property = " isDel" column = " is_del" jdbcType = " VARCHAR" />
< result property = " createTime" column = " create_time" jdbcType = " TIMESTAMP" />
< result property = " updateTime" column = " update_time" jdbcType = " TIMESTAMP" />
</ resultMap>
< select id = " login" resultMap = " UserMap" >
select * from user where phone = #{phone} and password = #{password}
</ select>
</ mapper>
将UserDao接口修改成如下:
package com. lagou. dao ;
import com. lagou. entity. User ;
import org. apache. ibatis. annotations. Param ;
public interface UserDao {
User login ( @Param ( "phone" ) String phone, @Param ( "password" ) String Password ) ;
}
在测试目录下,创建类:
package user ;
import com. lagou. dao. UserDao ;
import com. lagou. entity. User ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath:spring/spring-dao.xml" } )
public class TestUser {
@Autowired
private UserDao userDao;
@Test
public void login ( ) {
User login = userDao. login ( "110" , "123" ) ;
System . out. println ( login) ;
}
}
进行测试,若成功,那么这里就操作完毕
lagou-edu-service(项目):
spring-service.xml
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns: dubbo= " http://code.alibabatech.com/schema/dubbo"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd" >
< dubbo: application name = " lagou-edu-service" />
< dubbo: registry address = " zookeeper://192.168.164.128:2181" />
< dubbo: annotation package = " com.lagou" />
< dubbo: provider timeout = " 60000" />
< bean id = " redisTemplate"
class = " org.springframework.data.redis.core.RedisTemplate" >
< property name = " connectionFactory" ref = " connectionFactory" > </ property>
</ bean>
< bean id = " connectionFactory"
class = " org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
< property name = " hostName" value = " 192.168.164.128" > </ property>
< property name = " port" value = " 6379" />
</ bean>
</ beans>
对应的UserService类及其实现类:
package com. lagou. service ;
import com. lagou. entity. User ;
public interface UserService {
User login ( String phone, String Password ) ;
}
package com. lagou. service. impl ;
import com. alibaba. dubbo. config. annotation. Service ;
import com. lagou. dao. UserDao ;
import com. lagou. entity. User ;
import com. lagou. service. UserService ;
import org. springframework. beans. factory. annotation. Autowired ;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public User login ( String phone, String Password ) {
User login = userDao. login ( phone, Password ) ;
return login;
}
}
接下来编写测试类:
package user ;
import com. lagou. dao. UserDao ;
import com. lagou. entity. User ;
import com. lagou. service. UserService ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath*:spring/spring-*.xml" } )
public class TestUser {
@Autowired
private UserService userService;
@Test
public void login ( ) {
User login = userService. login ( "110" , "123" ) ;
System . out. println ( login) ;
}
}
执行成功,那么这里也就操作完成
接下来我们打开dubbo的管理端(79章博客说明过)
然后在该项目里,创建web项目,对应的pom.xml:
< packaging> war</ packaging>
< build>
< plugins>
< plugin>
< groupId> org.apache.tomcat.maven</ groupId>
< artifactId> tomcat7-maven-plugin</ artifactId>
< configuration>
< port> 8001</ port>
< path> /</ path>
</ configuration>
< executions>
< execution>
< phase> package</ phase>
< goals>
< goal> run</ goal>
</ goals>
</ execution>
</ executions>
</ plugin>
</ plugins>
</ build>
对应的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns = " http://xmlns.jcp.org/xml/ns/javaee"
xsi: schemaLocation= " http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id = " WebApp_ID" version = " 3.1" >
< listener>
< listenerclass> org.springframework.web.context.ContextLoaderListener</ listener-class>
</ listener>
< context-param>
< param-name> contextConfigLocation</ param-name>
< param-value> classpath*:spring/spring-*.xml</ param-value>
</ context-param>
</ web-app>
接下来打包运行,查看管理端是否上线即可,上线了,那么操作完成
总体目录如下:
lagou-edu-web项目:
这是一个新的项目,不是子项目:
将原来的服务方的父工程的依赖复制到这个项目里
并添加对应service的依赖(实际上只要实体类依赖即可,也最好导入实体类依赖,减少操作)
使得操作他的信息,注意需要先安装他的jar包才可
并且设置war包方式
将打包运行的端口由原来的8001修改成8002,并加上下面的依赖:
< dependency>
< groupId> com.thetransactioncompany</ groupId>
< artifactId> cors-filter</ artifactId>
< version> 2.5</ version>
</ dependency>
spring-consumer.xml:
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns = " http://www.springframework.org/schema/beans"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns: dubbo= " http://code.alibabatech.com/schema/dubbo"
xmlns: mvc= " http://www.springframework.org/schema/mvc"
xsi: schemaLocation= "
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd" >
< mvc: annotation-driven>
< mvc: message-converters register-defaults = " true" >
< bean
class = " com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" >
< property name = " supportedMediaTypes" value = " application/json" />
< property name = " features" >
< array>
< value> WriteMapNullValue</ value>
< value> WriteDateUseDateFormat</ value>
</ array>
</ property>
</ bean>
</ mvc: message-converters>
</ mvc: annotation-driven>
< dubbo: application name = " lagou-edu-web" />
< dubbo: registry address = " zookeeper://192.168.164.128:2181" />
< dubbo: annotation package = " com.lagou.controller" />
</ beans>
对应的UserController类:
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. entity. User ;
import com. lagou. service. UserService ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "/user" )
public class UserController {
@Reference
private UserService userService;
@GetMapping ( "login" )
public User login ( String phone, String password) {
System . out. println ( phone) ;
System . out. println ( password) ;
User login = userService. login ( phone, password) ;
System . out. println ( login) ;
return login;
}
}
对应的接口:
package com. lagou. service ;
import com. lagou. entity. User ;
public interface UserService {
User login ( String phone, String Password ) ;
}
注意:这个接口需要与服务器的包路径一致,否则可能会报错,因为要去调用对应的服务
自然会去对应的zookeeper的对应节点获取信息(根据自己的接口来得到),而该节点一般是对应的接口路径(实现类实现的接口)
所以一般需要相同路径,否则可能会报空指针异常,具体的dubbo的解释,可以去看79章博客
实际上别名是可以设置一样的,因为对应的zookeeper的不只是别名唯一
对应的页面index.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/login"> <!--不写method,则默认get请求-->
<p><input type="text" placeholder="请输入手机号..." name="phone"></p>
<p><input type="text" placeholder="请输入密码..." name="password"></p>
<p><button>登录</button></p>
</form>
</body>
</html>
对应的web.xml:
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns = " http://xmlns.jcp.org/xml/ns/javaee"
xsi: schemaLocation= " http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id = " WebApp_ID" version = " 3.1" >
< filter>
< filter-name> charset</ filter-name>
< filter-class> org.springframework.web.filter.CharacterEncodingFilter</ filter-class>
< init-param>
< param-name> encoding</ param-name>
< param-value> utf-8</ param-value>
</ init-param>
< init-param>
< param-name> forceEncoding</ param-name>
< param-value> true</ param-value>
</ init-param>
</ filter>
< filter-mapping>
< filter-name> charset</ filter-name>
< url-pattern> /*</ url-pattern>
</ filter-mapping>
< filter>
< filter-name> corsFitler</ filter-name>
< filter-class> com.thetransactioncompany.cors.CORSFilter</ filter-class>
</ filter>
< filter-mapping>
< filter-name> corsFitler</ filter-name>
< url-pattern> /*</ url-pattern>
</ filter-mapping>
< servlet>
< servlet-name> springMVC</ servlet-name>
< servlet-class> org.springframework.web.servlet.DispatcherServlet</ servlet-class>
< init-param>
< param-name> contextConfigLocation</ param-name>
< param-value> classpath:spring/spring-consumer.xml</ param-value>
</ init-param>
</ servlet>
< servlet-mapping>
< servlet-name> springMVC</ servlet-name>
< url-pattern> /</ url-pattern>
</ servlet-mapping>
</ web-app>
打包运行后,访问页面进行测试,然后查看对应的dubbo管理端,看看是否上线,若上线显示正常,则操作成功
至此登录完成,但是我们发现,对应的返回的数据中并没有特别的信息,只有对象的数据
前面说过一个接口响应格式 ,接下来我们使用这个格式来操作
在对应的lagou-edu-entity项目里的entity包里,加上对应的UserDTO类:
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserDTO < T > implements Serializable {
private static final long serialVersionUID = 1L ;
private int state;
private String message;
private T content;
}
上面修改后,记得安装,使得被依赖导入(刷新)
修改lagou-edu-web项目的UserController类:
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. entity. User ;
import com. lagou. entity. UserDTO ;
import com. lagou. service. UserService ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "/user" )
public class UserController {
@Reference
private UserService userService;
@GetMapping ( "login" )
public UserDTO login ( String phone, String password) {
UserDTO userDTO = new UserDTO < > ( ) ;
System . out. println ( phone) ;
System . out. println ( password) ;
User login = userService. login ( phone, password) ;
if ( login != null ) {
userDTO. setState ( 200 ) ;
userDTO. setMessage ( "登录成功" ) ;
} else {
userDTO. setState ( 300 ) ;
userDTO. setMessage ( "登录失败" ) ;
}
userDTO. setContent ( login) ;
System . out. println ( login) ;
return userDTO;
}
}
若成功,则返回的toString()根据注解的返回的顺序应该是按照对应编码值顺序显示的(大概是注解的作用)
所以对应的返回的数据中,是content先显示,然后是message,最后是state
实际上就是变成json时,会根据编码值来操作,注解的作用
至此,返回数据,操作完成,但是这只是登录完成,现在我们操作注册
要操作注册,首先我们需要对应的方法
在lagou-edu-dao项目的UserDao接口里面,添加如下方法,对应的UserDao接口如下:
package com. lagou. dao ;
import com. lagou. entity. User ;
import org. apache. ibatis. annotations. Param ;
public interface UserDao {
User login ( @Param ( "phone" ) String phone, @Param ( "password" ) String Password ) ;
Integer checkPhone ( String phone) ;
Integer register ( @Param ( "phone" ) String phone, @Param ( "password" ) String Password ) ;
}
添加对应的UserDao.xml:
< select id = " checkPhone" resultType = " integer" >
select count(*) from user where phone = #{phone}
</ select>
< insert id = " register" parameterType = " string" >
insert into user
(name,phone,password,create_time,update_time)
values
(#{phone},#{phone},#{password},sysdate(),sysdate())
</ insert>
在对应的测试类TestUser里添加如下代码进行测试:
@Test
public void checkPhone ( ) {
Integer integer = userDao. checkPhone ( "110" ) ;
System . out. println ( integer) ;
}
@Test
public void register ( ) {
Integer integer = userDao. register ( "115" , "123123" ) ;
System . out. println ( integer) ;
}
测试完成
同理在对应的lagou-edu-service项目的impl包里操作对应的类:
添加对应的方法放在UserService类:
Integer checkPhone ( String phone) ;
Integer register ( String phone, String Password ) ;
对应实现类也添加方法:
@Override
public Integer checkPhone ( String phone) {
Integer integer = userDao. checkPhone ( phone) ;
return integer;
}
@Override
public Integer register ( String phone, String Password ) {
Integer register = userDao. register ( phone, Password ) ;
return register;
}
对应的测试类也添加方法:
@Test
public void checkPhone ( ) {
Integer integer = userService. checkPhone ( "110" ) ;
System . out. println ( integer) ;
}
@Override
public Integer register ( String phone, String Password ) {
Integer register = userDao. register ( phone, Password ) ;
return register;
}
一般是没有问题的,记得执行测试类的对应方法,防止出现问题
接下来为了解决前面的功能描述,有手机号登录,没有则注册登录
那么进入到lagou-edu-web项目下,修改对应的UserController类(注意复制对应的方法到对应的接口里面):
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. entity. User ;
import com. lagou. entity. UserDTO ;
import com. lagou. service. UserService ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "/user" )
public class UserController {
@Reference
private UserService userService;
@GetMapping ( "login" )
public UserDTO login ( String phone, String password) {
UserDTO userDTO = new UserDTO < > ( ) ;
System . out. println ( phone) ;
System . out. println ( password) ;
User login = null ;
Integer integer = userService. checkPhone ( phone) ;
if ( integer == 0 ) {
userService. register ( phone, password) ;
userDTO. setMessage ( "手机号尚未注册,系统已帮您自动注册,请牢记密码!" ) ;
login = userService. login ( phone, password) ;
} else {
login = userService. login ( phone, password) ;
if ( login != null ) {
userDTO. setState ( 200 ) ;
userDTO. setMessage ( "登录成功" ) ;
} else {
userDTO. setState ( 300 ) ;
userDTO. setMessage ( "登录失败" ) ;
}
}
userDTO. setContent ( login) ;
System . out. println ( login) ;
return userDTO;
}
}
课程模块(与之前的操作VO以及单纯实体类(考虑DTO(97章博客有说明)的部分,但是是分开的)不同的是,这里我们放在一起,这是建立在我们只需要一个查询,多次使用,与VO各有好处,虽然这一次比较久,但可以多次使用,并且由于是多次使用,那么自然建立在层级上,所以存在外键的类可以选择不加(也可以加,一般不加而已)其外键对应主键(该主键不是外键,并且一般我们以他为主)的信息,因为是移动,自然可以直接的拿取的,但是考虑到数据非常多的情况下,你的移动只要够好,还是可以避免的,这需要前端的操作了,总不能全部移动吧,那这样还是选择访问数据库吧(前提是量大,否则连接的时间都可能超不过,考虑到总访问时间与部分的去除,按照忍受程度还需要考虑部分访问)):
当然,一次查询虽然看起来并不像多次的连接数据库(数据操作交给前端,后端就不用查询并使用数据库再操作了),但是由于是一次的,在维护方面并不友好,所以看个人意愿的,解决的方案有很多,并且结构也有很多,但是都需要根据具体情况来操作,当然,我们都建议使用维护,所以以后建议不一起处理(再97章博客中的大改造是对连表这个方面的处理,来进行维护的,即维护xml,而分开后是维护具体逻辑,这都是往维护性进行处理,从一段时间处理一次,到一段时间处理多次,到长时间中会处理多次(因为容易继续访问),时间跨大了)
全部课程:
对应的部分案例:
课程:Java从小白到大神 (course) -------> 起点老师:拉勾网高级讲师 (teacher)
第一章:初识 (course_section)
01 什么是java (course_lesson)
02 jdk的介绍与安装
第二章:应用
01 什么是数据类型
02 什么是变量
course 1:1 teacher
course 1:N course_section
course_section 1:N course_lesson
course_lesson1:N course_media
在lagou-edu-entity项目的entity包里加上如下的类:
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class ActivityCourse implements Serializable {
private static final long serialVersionUID = - 89461375082427542L ;
private Integer id;
private Integer courseId;
private Date beginTime;
private Date endTime;
private Long amount;
private Integer stock;
private Integer status;
private Integer isDel;
private String remark;
private Date createTime;
private String createUser;
private Date updateTime;
private String updateUser;
}
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. io. Serializable ;
import java. util. Date ;
import java. util. List ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Course implements Serializable {
private Teacher teacher;
private List < CourseSection > courseSectionList;
private ActivityCourse activityCourse;
private static final long serialVersionUID = 464248821202087847L ;
private Object id;
private String courseName;
private String brief;
private Object price;
private String priceTag;
private Object discounts;
private String discountsTag;
private String courseDescriptionMarkDown;
private String courseDescription;
private String courseImgUrl;
private Integer isNew;
private String isNewDes;
private Integer lastOperatorId;
private Date autoOnlineTime;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer totalDuration;
private String courseListImg;
private Integer status;
private Integer sortNum;
private String previewFirstField;
private String previewSecondField;
private Integer sales;
}
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseLesson implements Serializable {
private CourseMedia courseMedia;
private static final long serialVersionUID = - 35857311228165600L ;
private Object id;
private Integer courseId;
private Integer sectionId;
private String theme;
private Integer duration;
private Integer isFree;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer orderNum;
private Integer status;
}
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseMedia implements Serializable {
private static final long serialVersionUID = 673974921818890080L ;
private Integer id;
private Integer courseId;
private Integer sectionId;
private Integer lessonId;
private String coverImageUrl;
private String duration;
private String fileEdk;
private Long fileSize;
private String fileName;
private String fileDk;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer durationNum;
private String fileId;
}
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
import java. util. List ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseSection implements Serializable {
private List < CourseLesson > courseLessonList;
private static final long serialVersionUID = 698702451600763670L ;
private Object id;
private Integer courseId;
private String sectionName;
private String description;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer orderNum;
private Integer status;
}
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Teacher implements Serializable {
private static final long serialVersionUID = 738571768582945875L ;
private Object id;
private Integer courseId;
private String teacherName;
private String position;
private String description;
private Date createTime;
private Date updateTime;
private Integer isDel;
}
我们发现,使用注解来生成对应的get,set或者其他方法时,我们好修改
也就是说,我们只需要修改或者添加变量即可,而不用每次的修改或者添加,都要手动的添加对应的get和set方法,或者其他方法
操作对应的lagou-edu-dao项目
在资源文件里的dao包中添加对应的CourseDao.xml:
<?xml version="1.0" encoding="UTF-8"?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-
mapper.dtd" >
< mapper namespace = " com.lagou.dao.CourseDao" >
< resultMap type = " com.lagou.entity.Course" id = " CourseMap" >
< result property = " id" column = " c_id" />
< result property = " courseName" column = " course_name" />
< result property = " brief" column = " brief" />
< result property = " price" column = " price" />
< result property = " priceTag" column = " price_tag" />
< result property = " discounts" column = " discounts" />
< result property = " discountsTag" column = " discounts_tag" />
< result property = " courseDescriptionMarkDown" column = " course_description_mark_down" />
< result property = " courseDescription" column = " course_description" />
< result property = " courseImgUrl" column = " course_img_url" />
< result property = " isNew" column = " is_new" />
< result property = " isNewDes" column = " is_new_des" />
< result property = " lastOperatorId" column = " last_operator_id" />
< result property = " autoOnlineTime" column = " auto_online_time" />
< result property = " createTime" column = " c_create_time" />
< result property = " updateTime" column = " c_update_time" />
< result property = " isDel" column = " c_is_del" />
< result property = " totalDuration" column = " total_duration" />
< result property = " courseListImg" column = " course_list_img" />
< result property = " status" column = " c_status" />
< result property = " sortNum" column = " sort_num" />
< result property = " previewFirstField" column = " preview_first_field" />
< result property = " previewSecondField" column = " preview_second_field" />
< result property = " sales" column = " sales" />
< association property = " teacher" javaType = " com.lagou.entity.Teacher" >
< result property = " id" column = " t_id" />
< result property = " courseId" column = " t_course_id" />
< result property = " teacherName" column = " teacher_name" />
< result property = " position" column = " position" />
< result property = " description" column = " t_description" />
< result property = " createTime" column = " t_create_time" />
< result property = " updateTime" column = " t_update_time" />
< result property = " isDel" column = " t_is_del" />
</ association>
< association property = " activityCourse" javaType = " com.lagou.entity.ActivityCourse" >
< result property = " id" column = " ac_id" />
< result property = " courseId" column = " ac_course_id" />
< result property = " beginTime" column = " begin_time" />
< result property = " endTime" column = " end_time" />
< result property = " amount" column = " amount" />
< result property = " stock" column = " stock" />
< result property = " status" column = " ac_status" />
< result property = " isDel" column = " ac_is_del" />
< result property = " remark" column = " remark" />
< result property = " createTime" column = " ac_create_time" />
< result property = " createUser" column = " create_user" />
< result property = " updateTime" column = " ac_update_time" />
< result property = " updateUser" column = " update_user" />
</ association>
< collection property = " courseSectionList" ofType = " com.lagou.entity.CourseSection" >
< result property = " id" column = " cs_id" />
< result property = " courseId" column = " cs_course_id" />
< result property = " sectionName" column = " section_name" />
< result property = " description" column = " cs_description" />
< result property = " createTime" column = " cs_create_time" />
< result property = " updateTime" column = " cs_update_time" />
< result property = " isDel" column = " cs_is_del" />
< result property = " orderNum" column = " cs_order_num" />
< result property = " status" column = " cs_status" />
< collection property = " courseLessonList" ofType = " com.lagou.entity.CourseLesson" >
< result property = " id" column = " cl_id" />
< result property = " courseId" column = " cl_course_id" />
< result property = " sectionId" column = " cl_section_id" />
< result property = " theme" column = " theme" />
< result property = " duration" column = " cl_duration" />
< result property = " isFree" column = " is_free" />
< result property = " createTime" column = " cl_create_time" />
< result property = " updateTime" column = " cl_update_time" />
< result property = " isDel" column = " cl_is_del" />
< result property = " orderNum" column = " cl_order_num" />
< result property = " status" column = " cl_status" />
< association property = " courseMedia" javaType = " com.lagou.entity.CourseMedia" >
< result property = " id" column = " cm_id" />
< result property = " courseId" column = " cm_course_id" />
< result property = " sectionId" column = " cm_section_id" />
< result property = " lessonId" column = " cm_lesson_id" />
< result property = " coverImageUrl" column = " cover_image_url" />
< result property = " duration" column = " cm_duration" />
< result property = " fileEdk" column = " file_edk" />
< result property = " fileSize" column = " file_size" />
< result property = " fileName" column = " file_name" />
< result property = " fileDk" column = " file_dk" />
< result property = " createTime" column = " cm_create_time" />
< result property = " updateTime" column = " cm_update_time" />
< result property = " isDel" column = " cm_is_del" />
< result property = " durationNum" column = " duration_num" />
< result property = " fileId" column = " file_id" />
</ association>
</ collection>
</ collection>
</ resultMap>
< select id = " getAllCourse" resultMap = " CourseMap" >
SELECT
c.`id` c_id,`course_name`,`brief`,`price`,`price_tag`,`discounts`,`discounts_tag`,
`course_description_mark_down`,`course_description`,`course_img_url`,`is_new`,
`is_new_des`,`last_operator_id`,`auto_online_time`,
c.`create_time` c_create_time,c.`update_time` c_update_time,
c.`is_del` c_is_del,`total_duration`,`course_list_img`,
c.`status` c_status,`sort_num`,`preview_first_field`,`preview_second_field`,
`sales`,
t.`id` t_id,t.`course_id` t_course_id,`teacher_name`,
`position`,t.`description` t_description,
t.`create_time` t_create_time,t.`update_time` t_update_time,t.`is_del` t_is_del,
cs.`id` cs_id,cs.`course_id` cs_course_id,`section_name`,
cs.`description` cs_description,cs.`create_time` cs_create_time,
cs.`update_time` cs_update_time,
cs.`is_del` cs_is_del,cs.`order_num` cs_order_num,cs.`status` cs_status,
cl.`id` cl_id,cl.`course_id` cl_course_id,cl.`section_id` cl_section_id,`theme`,
cl.`duration` cl_duration,`is_free`,cl.`create_time` cl_create_time,
cl.`update_time` cl_update_time,cl.`is_del` cl_is_del,
cl.`order_num` cl_order_num,cl.`status` cl_status,
cm.`id` cm_id,cm.`course_id` cm_course_id,cm.`section_id` cm_section_id,
cm.`lesson_id` cm_lesson_id,
`cover_image_url`,
cm.`duration` cm_duration,`file_edk`,`file_size`,
`file_name`,`file_dk`,cm.`create_time` cm_create_time,
cm.`update_time` cm_update_time,cm.`is_del` cm_is_del,`duration_num`,`file_id`,
ac.id ac_id,ac.course_id ac_course_id,
`begin_time`,`end_time`,`amount`,`stock`,ac.`status` ac_status,
ac.`is_del` ac_is_del,`remark`,ac.`create_time`
ac_create_time,`create_user`,ac.`update_time` ac_update_time,`update_user`
FROM
activity_course ac RIGHT JOIN course c ON c.`id` = ac.`course_id`
INNER JOIN teacher t ON c.id = t.`course_id`
INNER JOIN course_section cs ON c.id = cs.`course_id`
INNER JOIN course_lesson cl ON cs.`id` = cl.`section_id`
LEFT JOIN course_media cm ON cm.`lesson_id` = cl.`id`
ORDER BY amount DESC,c_id ,ac_create_time DESC
</ select>
</ mapper>
上面是全部查询,也就是根据课程,查询对应的章节,小节,视频,讲师,等等,5个表进行联查
对应的xml写好后,我们写上对应的接口,在dao包下写上CourseDao接口:
package com. lagou. dao ;
import com. lagou. entity. Course ;
import java. util. List ;
public interface CourseDao {
List < Course > getAllCourse ( ) ;
}
在测试的地方,添加course包,然后添加测试类TestCourse:
package course ;
import com. lagou. dao. CourseDao ;
import com. lagou. entity. Course ;
import com. lagou. entity. CourseLesson ;
import com. lagou. entity. CourseMedia ;
import com. lagou. entity. CourseSection ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
import java. util. List ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath:spring/spring-dao.xml" } )
public class TestCourse {
@Autowired
private CourseDao courseDao;
@Test
public void getAllCourse ( ) {
List < Course > allCourse = courseDao. getAllCourse ( ) ;
System . out. println ( allCourse) ;
System . out. println ( "-------------------------" ) ;
for ( Course course : allCourse) {
String flag = course. getActivityCourse ( ) != null ? "火爆活动中" : "" ;
System . out. println ( "课程:" + flag + " " + course. getId ( ) + "->" + course. getCourseName ( ) ) ;
for ( CourseSection cs : course. getCourseSectionList ( ) ) {
System . out. println ( "\t\t章节:" + cs. getId ( ) + "->" + cs. getSectionName ( ) ) ;
for ( CourseLesson cl : cs. getCourseLessonList ( ) ) {
if ( cl. getCourseMedia ( ) == null ) {
cl. setCourseMedia ( new CourseMedia ( ) ) ;
}
System . out. println ( "\t\t\t小节:" + cl. getId ( ) + "->" + cl. getTheme ( ) +
",视频:" + cl. getCourseMedia ( ) . getFileId ( ) +
",时长:【" + cl. getCourseMedia ( ) . getDuration ( ) + "】" ) ;
}
}
}
}
}
进行测试,若成功,则操作完毕
这里回顾一下,一般当查询出多个数据时,需要使用集合来保存,如List,若就是单纯的一个返回类型,那么会报错
除非查询的数据只有一条(也包括有很多内部数据使得主方变成多条数据)
那么就不会报错(无论是全查还是条件查,只要是一条或者严谨来说是主方一条,就不会)
当然,无论是多条还是单条,集合都可以操作
再在对应的lagou-edu-service项目里的lagou包里面加上course包,course包加上对应的接口CourseService及其实现类
package com. lagou. course ;
import com. lagou. entity. Course ;
import java. util. List ;
public interface CourseService {
List < Course > getAllCourse ( ) ;
}
package com. lagou. course. impl ;
import com. alibaba. dubbo. config. annotation. Service ;
import com. lagou. course. CourseService ;
import com. lagou. dao. CourseDao ;
import com. lagou. entity. Course ;
import org. springframework. beans. factory. annotation. Autowired ;
import java. util. List ;
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseDao courseDao;
@Override
public List < Course > getAllCourse ( ) {
return courseDao. getAllCourse ( ) ;
}
}
在lagou-edu-web里的lagou包下,创建course包,加上对应的CourseService接口
package com. lagou. course ;
import com. lagou. entity. Course ;
import java. util. List ;
public interface CourseService {
List < Course > getAllCourse ( ) ;
}
在对应的controller包里。加上CourseController类:
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. course. CourseService ;
import com. lagou. entity. Course ;
import com. lagou. entity. User ;
import com. lagou. entity. UserDTO ;
import com. lagou. service. UserService ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@RestController
@RequestMapping ( "/course" )
public class CourseController {
@Reference
private CourseService courseService;
@GetMapping ( "getAllCourse" )
public List < Course > getAllCourse ( String phone, String password) {
List < Course > allCourse = courseService. getAllCourse ( ) ;
return allCourse;
}
}
进行测试,若成功返回数据,则操作完毕
至此,应该明白,对应的分布式系统为什么是用RPC来进行远程调用了吧
即在模块之间进行方法细分(服务器),这些细分互相调用
使得原来可能有同一个方法的多个服务器,只需要去这一个服务器调用方法即可,即相同服务抽取出来了(虽然这里并没有体现)
已购课程 :
在对应的CourseDao.xml加上如下的配置:
< sql id = " courseInfo" >
SELECT
c.`id` c_id,`course_name`,`brief`,`price`,`price_tag`,`discounts`,`discounts_tag`,
`course_description_mark_down`,`course_description`,`course_img_url`,`is_new`,
`is_new_des`,`last_operator_id`,`auto_online_time`,
c.`create_time` c_create_time,c.`update_time` c_update_time,
c.`is_del` c_is_del,`total_duration`,`course_list_img`,
c.`status` c_status,`sort_num`,`preview_first_field`,`preview_second_field`,
`sales`,
t.`id` t_id,t.`course_id` t_course_id,`teacher_name`,
`position`,t.`description` t_description,
t.`create_time` t_create_time,t.`update_time` t_update_time,t.`is_del` t_is_del,
cs.`id` cs_id,cs.`course_id` cs_course_id,`section_name`,
cs.`description` cs_description,cs.`create_time` cs_create_time,
cs.`update_time` cs_update_time,
cs.`is_del` cs_is_del,cs.`order_num` cs_order_num,cs.`status` cs_status,
cl.`id` cl_id,cl.`course_id` cl_course_id,cl.`section_id` cl_section_id,`theme`,
cl.`duration` cl_duration,`is_free`,cl.`create_time` cl_create_time,
cl.`update_time` cl_update_time,cl.`is_del` cl_is_del,
cl.`order_num` cl_order_num,cl.`status` cl_status,
cm.`id` cm_id,cm.`course_id` cm_course_id,cm.`section_id` cm_section_id,
cm.`lesson_id` cm_lesson_id,
`cover_image_url`,
cm.`duration` cm_duration,`file_edk`,`file_size`,
`file_name`,`file_dk`,cm.`create_time` cm_create_time,
cm.`update_time` cm_update_time,cm.`is_del` cm_is_del,`duration_num`,`file_id`,
ac.id ac_id,ac.course_id ac_course_id,
`begin_time`,`end_time`,`amount`,`stock`,ac.`status` ac_status,
ac.`is_del` ac_is_del,`remark`,ac.`create_time`
ac_create_time,`create_user`,ac.`update_time` ac_update_time,`update_user`
FROM
activity_course ac RIGHT JOIN course c ON c.`id` = ac.`course_id`
INNER JOIN teacher t ON c.id = t.`course_id`
INNER JOIN course_section cs ON c.id = cs.`course_id`
INNER JOIN course_lesson cl ON cs.`id` = cl.`section_id`
LEFT JOIN course_media cm ON cm.`lesson_id` = cl.`id`
</ sql>
< select id = " getCourseByUserId" resultMap = " CourseMap" >
< include refid = " courseInfo" />
WHERE c.id IN ( SELECT course_id FROM user_course_order WHERE STATUS = 20
AND is_del = 0 AND user_id = #
{userid})
ORDER BY amount DESC,c_id ,ac_create_time DESC
</ select>
添加部分CourseDao接口:
List < Course > getCourseByUserId ( String userId) ;
添加部分TestCourse类的测试方法:
@Test
public void getCourseByUserId ( ) {
List < Course > allCourse = courseDao. getCourseByUserId ( "100030018" ) ;
System . out. println ( allCourse) ;
System . out. println ( "-------------------------" ) ;
for ( Course course : allCourse) {
String flag = course. getActivityCourse ( ) != null ? "火爆活动中" : "" ;
System . out. println ( "课程:" + flag + " " + course. getId ( ) + "->" + course. getCourseName ( ) ) ;
for ( CourseSection cs : course. getCourseSectionList ( ) ) {
System . out. println ( "\t\t章节:" + cs. getId ( ) + "->" + cs. getSectionName ( ) ) ;
for ( CourseLesson cl : cs. getCourseLessonList ( ) ) {
if ( cl. getCourseMedia ( ) == null ) {
cl. setCourseMedia ( new CourseMedia ( ) ) ;
}
System . out. println ( "\t\t\t小节:" + cl. getId ( ) + "->" + cl. getTheme ( ) +
",视频:" + cl. getCourseMedia ( ) . getFileId ( ) +
",时长:【" + cl. getCourseMedia ( ) . getDuration ( ) + "】" ) ;
}
}
}
}
在lagou-edu-service添加部分的接口和实现类:
List < Course > getCourseByUserId ( String userId) ;
@Override
public List < Course > getCourseByUserId ( String userId) {
List < Course > courseByUserId = courseDao. getCourseByUserId ( userId) ;
return courseByUserId;
}
并不是所有的都需要测试,但测试还是好的,若要测的话,自己进行测试即可,这里就不写了
这时在lagou-edu-web添加部分接口(记得对应包):
List < Course > getCourseByUserId ( String userId) ;
添加部分CourseController类:
@GetMapping ( "getCourseByUserId/{userid}" )
public List < Course > getCourseByUserId ( @PathVariable ( "userid" ) String userid) {
List < Course > allCourse = courseService. getCourseByUserId ( userid) ;
return allCourse;
}
接下来启动测试,查看是否有返回值,若有,则操作成功
课程详情:
在对应的lagou-edu-dao里加上对应的配置:
添加部分CourseDao.xml:
< select id= "getCourseById" resultMap= "CourseMap" >
< include refid= "courseInfo" / >
where c. id = #{ courseId}
< / select>
添加部分CourseDao接口:
Course getCourseById ( Integer cid) ;
对应的测试方法:
@Test
public void getCourseById ( ) {
Course courseById = courseDao. getCourseById ( 7 ) ;
System . out. println ( courseById) ;
}
在对应的lagou-edu-service里添加部分CourseService接口及其实现类:
Course getCourseById ( Integer cid) ;
@Override
public Course getCourseById ( Integer cid) {
Course courseById = courseDao. getCourseById ( cid) ;
return courseById;
}
对应的lagou-edu-web项目里,添加部分CourseService:
Course getCourseById ( Integer cid) ;
添加部分的CourseController:
@GetMapping ( "getCourseById/{courseid}" )
public Course getCourseById ( @PathVariable ( "courseid" ) Integer courseid) {
Course allCourse = courseService. getCourseById ( courseid) ;
return allCourse;
}
启动测试,若返回数据,则操作成功
订单模块 :
购买,生成订单
在dao层的项目中,添加对应的OrderDao.xml:
<?xml version="1.0" encoding="UTF-8"?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-
mapper.dtd" >
< mapper namespace = " com.lagou.dao.OrderDao" >
< insert id = " saveOrder" >
INSERT INTO `user_course_order`
(`order_no`,`user_id`,`course_id`,`activity_course_id`,
`source_type`,`status`,`create_time`,`update_t
ime`,`is_del`)
VALUES
(#{orderNo},#{user_id},#{course_id},#{activity_course_id},#
{source_type},0,sysdate(),sysdate(),0);
</ insert>
</ mapper>
添加对应的接口:
package com. lagou. dao ;
import com. lagou. entity. User ;
import org. apache. ibatis. annotations. Param ;
public interface OrderDao {
public void saveOrder ( @Param ( "orderNo" ) String orderNo,
@Param ( "user_id" ) String user_id,
@Param ( "course_id" ) String course_id,
@Param ( "activity_course_id" ) String activity_course_id,
@Param ( "source_type" ) String source_type) ;
}
在对应的service层的项目里,加上对应的包并添加OrderService接口及其实现类:
package com. lagou. order ;
import org. apache. ibatis. annotations. Param ;
public interface OrderService {
public void saveOrder ( String orderNo, String user_id, String course_id,
String activity_course_id, String source_type) ;
}
package com. lagou. order. impl ;
import com. alibaba. dubbo. config. annotation. Service ;
import com. lagou. dao. OrderDao ;
import com. lagou. order. OrderService ;
import org. springframework. beans. factory. annotation. Autowired ;
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Override
public void saveOrder ( String orderNo, String user_id, String course_id, String
activity_course_id, String source_type) {
orderDao. saveOrder ( orderNo, user_id, course_id, activity_course_id, source_type) ;
}
}
添加对应的测试类:
package order ;
import com. lagou. order. OrderService ;
import com. lagou. service. UserService ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
import java. util. UUID ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath*:spring/spring-*.xml" } )
public class TestOrder {
@Autowired
private OrderService orderService;
@Test
public void saveOrder ( ) {
String orderNo = UUID . randomUUID ( ) . toString ( ) ;
String user_id= "100030011" ;
String course_id= "7" ;
String activity_course_id= "0" ;
String source_type= "1" ;
orderService. saveOrder ( orderNo, user_id, course_id, activity_course_id, source_type) ;
}
}
若添加数据成功,即数据库有对应数据了,那么操作完成
在web层项目里,添加部分接口(记得包路径一致):
package com. lagou. order ;
public interface OrderService {
public void saveOrder ( String orderNo, String user_id, String course_id, String activity_course_id,
String source_type) ;
}
添加对应的OrderController类:
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. entity. Course ;
import com. lagou. order. OrderService ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
import java. util. UUID ;
@RestController
@RequestMapping ( "/order" )
public class OrderController {
@Reference
private OrderService orderService;
@GetMapping ( "saveOrder/{userid}/{courseid}/{acid}/{stype}" )
public String saveOrder ( @PathVariable ( "userid" ) String userid, @PathVariable ( "courseid" ) String
courseid, @PathVariable ( "acid" ) String acid, @PathVariable ( "stype" ) String stype) {
String orderNo = UUID . randomUUID ( ) . toString ( ) ;
orderService. saveOrder ( orderNo, userid, courseid, acid, stype) ;
return orderNo;
}
}
启动测试,若返回数据,则操作成功(记得对应的userid好像是不能重复的,对应表有这样的索引)
注意:唯一的索引在字段后面直接的设置才算完整,若使用索引方式来设置多个字段的索引,那么有如下的操作
第一,根据多个字段是总体是否相同,来进行唯一,也就是说,只要部分不同,那么其他部分可以相同
但若设置完后,那么设置的就基本固定,这时无论怎么操作都基本不会与前面的数据操作该唯一,但新加的会,即没有设置完的
第二,null的值,是默认null,不参与唯一,也就是直接忽略
而不是null字符串,要消除该字符串null,需要先设置一个值
再手动设置null就变成默认的null,否则不会变,即要先设置使得消除固定
满足这两点,使得有唯一
根据上面的解释,所以,最好是直接的设置在字段后面
订单操作:
更新的接口路径这里进行了改变,往下看就知道了
再次操作dao层项目,添加对应的OrderDao接口和该接口的配置:
Integer updateOrder ( @Param ( "orderNo" ) String orderNo, @Param ( "status" ) Integer status) ;
< update id = " updateOrder" >
update user_course_order set status = #{status} where order_no = #{orderNo} and is_del = 0
</ update>
对应的service层的接口和实现类:
Integer updateOrder ( String orderNo, Integer status) ;
@Override
public Integer updateOrder ( String orderNo, Integer status) {
Integer integer = orderDao. updateOrder ( orderNo, status) ;
return integer;
}
对应的web层的接口:
Integer updateOrder ( String orderNo, Integer status) ;
对应的部分OrderController:
@GetMapping ( "updateOrder/{orderno}//{status}" )
public Integer updateOrder ( @PathVariable ( "orderno" ) String orderno, @PathVariable ( "status" )
Integer
status) {
Integer integer = orderService. updateOrder ( orderno, status) ;
return integer;
}
启动测试,若返回数据,且对应的数据库的状态也变化了则操作成功
接下来继续在dao层项目里加上对应的接口和配置文件:
Integer deleteOrder ( @Param ( "orderNo" ) String orderNo) ;
< update id = " deleteOrder" >
update user_course_order set is_del = 1 where order_no = #{orderNo}
</ update>
加上对应的service层的接口和实现类:
Integer deleteOrder ( String orderNo) ;
@Override
public Integer deleteOrder ( String orderNo) {
Integer integer = orderDao. deleteOrder ( orderNo) ;
return integer;
}
对应的web层项目的接口:
Integer deleteOrder ( @Param ( "orderNo" ) String orderNo) ;
对应的部分OrderController类:
@GetMapping ( "deleteOrder/{orderno}" )
public Integer deleteOrder ( @PathVariable ( "orderno" ) String orderno) {
Integer integer = orderService. deleteOrder ( orderno) ;
return integer;
}
启动测试,若返回数据,且对应的数据库的对应字段也变化了则操作成功
接下来为了查询我的订单,需要对应的订单实体类:
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsConstructor ;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserCourseOrder implements Serializable {
private static final long serialVersionUID = - 77239403959527764L ;
private Long id;
private String orderNo;
private Object userId;
private Object courseId;
private Integer activityCourseId;
private Object sourceType;
private Object status;
private Date createTime;
private Date updateTime;
private Object isDel;
}
对应的dao层的接口及其配置文件:
List < UserCourseOrder > getOrdersByUserId ( @Param ( "userId" ) String userId) ;
< resultMap type = " com.lagou.entity.UserCourseOrder" id = " UserCourseOrderMap" >
< result property = " id" column = " id" jdbcType = " INTEGER" />
< result property = " orderNo" column = " order_no" jdbcType = " VARCHAR" />
< result property = " userId" column = " user_id" jdbcType = " VARCHAR" />
< result property = " courseId" column = " course_id" jdbcType = " VARCHAR" />
< result property = " activityCourseId" column = " activity_course_id" jdbcType = " INTEGER" />
< result property = " sourceType" column = " source_type" jdbcType = " VARCHAR" />
< result property = " status" column = " status" jdbcType = " VARCHAR" />
< result property = " createTime" column = " create_time" jdbcType = " TIMESTAMP" />
< result property = " updateTime" column = " update_time" jdbcType = " TIMESTAMP" />
< result property = " isDel" column = " is_del" jdbcType = " VARCHAR" />
</ resultMap>
< select id = " getOrdersByUserId" resultMap = " UserCourseOrderMap" >
select * from user_course_order where is_del = 0 and user_id = #{userId}
</ select>
对应的service层项目的接口和实现类:
List < UserCourseOrder > getOrdersByUserId ( String userId) ;
@Override
public List < UserCourseOrder > getOrdersByUserId ( String userId) {
List < UserCourseOrder > ordersByUserId = orderDao. getOrdersByUserId ( userId) ;
return ordersByUserId;
}
对应的web层项目的接口:
List < UserCourseOrder > getOrdersByUserId ( String userId) ;
对应的部分OrderController类:
@GetMapping ( "getOrdersByUserId/{userId}" )
public List < UserCourseOrder > getOrdersByUserId ( @PathVariable ( "userId" ) String userId) {
List < UserCourseOrder > ordersByUserId = orderService. getOrdersByUserId ( userId) ;
return ordersByUserId;
}
启动测试,若返回数据,则操作成功
留言模块:
保存留言
添加实体类:
package com. lagou. entity ;
import lombok. AllArgsConstructor ;
import lombok. Data ;
import lombok. NoArgsC onstructor;
import lombok. ToString ;
import java. util. Date ;
import java. io. Serializable ;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CourseComment implements Serializable {
private static final long serialVersionUID = - 11641570368573216L ;
private Object id;
private Integer courseId;
private Integer sectionId;
private Integer lessonId;
private Integer userId;
private String userName;
private Integer parentId;
private Integer isTop;
private String comment;
private Integer likeCount;
private Integer isReply;
private Integer type;
private Integer status;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer lastOperator;
private Integer isNotify;
private Integer markBelong;
private Integer replied;
}
在对应的dao层项目中的dao包下,记得加上对应的接口(类文件夹)和配置文件(资源文件夹),即添加接口及其配置文件:
package com. lagou. dao ;
import com. lagou. entity. CourseComment ;
public interface CourseCommentDao {
Integer saveComment ( CourseComment courseComment) ;
}
<?xml version="1.0" encoding="UTF-8"?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-
mapper.dtd" >
< mapper namespace = " com.lagou.dao.CourseCommentDao" >
< insert id = " saveComment" >
insert into `course_comment`
(`course_id`,`section_id`,`lesson_id`,
`user_id`,`user_name`,`parent_id`,
`is_top`,`comment`,`like_count`,
`is_reply`,`type`,`status`,
`create_time`,`update_time`,
`is_del`,`last_operator`,`is_notify`,`mark_belong`,`replied`) values
(#{courseId},#{sectionId},#{lessonId},
#{userId},#{userName},#{parentId},
0,#{comment},0,0,
#{type},0,sysdate(),sysdate(),0,#{lastOperator},1,0,0)
</ insert>
</ mapper>
对应的service层的项目中的lagou的包下,添加comment包,并加上对应的接口及其实现类:
package com. lagou. comment ;
import com. lagou. entity. CourseComment ;
public interface CommentService {
Integer saveComment ( CourseComment courseComment) ;
}
package com. lagou. comment. impl ;
import com. alibaba. dubbo. config. annotation. Service ;
import com. lagou. comment. CommentService ;
import com. lagou. dao. CourseCommentDao ;
import com. lagou. entity. CourseComment ;
import org. springframework. beans. factory. annotation. Autowired ;
@Service
public class CommentServiceImpl implements CommentService {
@Autowired
private CourseCommentDao courseCommentDao;
@Override
public Integer saveComment ( CourseComment courseComment) {
Integer integer = courseCommentDao. saveComment ( courseComment) ;
return integer;
}
}
添加对应的测试包comment,再在该包里加上测试类TestComment类:
package comment ;
import com. lagou. comment. CommentService ;
import com. lagou. entity. CourseComment ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. test. context. ContextConfiguration ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
@RunWith ( SpringJUnit4ClassRunner . class )
@ContextConfiguration ( locations = { "classpath*:spring/spring-*.xml" } )
public class TestComment {
@Autowired
private CommentService commentService;
@Test
public void saveComment ( ) {
CourseComment courseComment = new CourseComment ( ) ;
courseComment. setCourseId ( 7 ) ;
courseComment. setSectionId ( 8 ) ;
courseComment. setLessonId ( 10 ) ;
courseComment. setUserId ( 100030011 ) ;
courseComment. setUserName ( "往事如烟" ) ;
courseComment. setParentId ( 0 ) ;
courseComment. setComment ( "吕奉先" ) ;
courseComment. setType ( 0 ) ;
courseComment. setLastOperator ( 100030011 ) ;
commentService. saveComment ( courseComment) ;
}
}
在对应web项目下,添加对应的接口(先创建对应的comment包):
package com. lagou. comment ;
import com. lagou. entity. CourseComment ;
public interface CommentService {
Integer saveComment ( CourseComment courseComment) ;
}
在对应的controller包下,添加CommentController类:
package com. lagou. controller ;
import com. alibaba. dubbo. config. annotation. Reference ;
import com. lagou. comment. CommentService ;
import com. lagou. course. CourseService ;
import com. lagou. entity. Course ;
import com. lagou. entity. CourseComment ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@RestController
@RequestMapping ( "course" )
public class CommentController {
@Reference
private CommentService commentService;
@GetMapping ( "comment/saveCourseComment" )
public Object saveCourseComment ( ) {
CourseComment courseComment = new CourseComment ( ) ;
courseComment. setCourseId ( 7 ) ;
courseComment. setSectionId ( 8 ) ;
courseComment. setLessonId ( 10 ) ;
courseComment. setUserId ( 100030011 ) ;
courseComment. setUserName ( "往事如烟" ) ;
courseComment. setParentId ( 0 ) ;
courseComment. setComment ( "吕奉先" ) ;
courseComment. setType ( 0 ) ;
courseComment. setLastOperator ( 100030011 ) ;
Integer integer = commentService. saveComment ( courseComment) ;
return integer;
}
}
启动测试,若数据库里添加了数据,那么操作成功
留言列表:
某门课程的全部留言
在dao层项目里加上部分CourseCommentDao接口及其配置文件:
List < CourseComment > getCommentsByCourseId ( @Param ( "courseId" ) Integer courseId, @Param ( "offset" )
Integer offset, @Param ( "pagesize" ) Integer pagesize) ;
< resultMap type = " com.lagou.entity.CourseComment" id = " CourseCommentMap" >
< result property = " id" column = " id" />
< result property = " courseId" column = " course_id" />
< result property = " sectionId" column = " section_id" />
< result property = " lessonId" column = " lesson_id" />
< result property = " userId" column = " user_id" />
< result property = " userName" column = " user_name" />
< result property = " parentId" column = " parent_id" />
< result property = " isTop" column = " is_top" />
< result property = " comment" column = " comment" />
< result property = " likeCount" column = " like_count" />
< result property = " isReply" column = " is_reply" />
< result property = " type" column = " type" />
< result property = " status" column = " status" />
< result property = " createTime" column = " create_time" />
< result property = " updateTime" column = " update_time" />
< result property = " isDel" column = " is_del" />
< result property = " lastOperator" column = " last_operator" />
< result property = " isNotify" column = " is_notify" />
< result property = " markBelong" column = " mark_belong" />
< result property = " replied" column = " replied" />
</ resultMap>
< select id = " getCommentsByCourseId" resultMap = " CourseCommentMap" >
SELECT * FROM course_comment
WHERE is_del = 0
AND course_id = #{courseId}
ORDER BY is_top DESC,like_count DESC,create_time DESC
LIMIT #{offset},#{pagesize}
</ select>
对应的service层的项目,添加对应的接口和实现类:
List < CourseComment > getCommentsByCourseId ( @Param ( "courseId" ) Integer courseId, @Param ( "offset" )
Integer offset, @Param ( "pagesize" ) Integer pagesize) ;
@Override
public List < CourseComment > getCommentsByCourseId ( Integer courseId, Integer offset, Integer
pagesize) {
List < CourseComment > commentsByCourseId =
courseCommentDao. getCommentsByCourseId ( courseId, offset, pagesize) ;
return commentsByCourseId;
}
对应的测试类方法:
@Test
public void getCommentsByCourseId ( ) {
int pageSize = 20 ;
int pageIndex = 1 ;
List < CourseComment > commentsByCourseId =
commentService. getCommentsByCourseId ( 1 , ( pageIndex - 1 ) * 20 , pageSize) ;
for ( int i = 0 ; i< commentsByCourseId. size ( ) ; i++ ) {
CourseComment courseComment = commentsByCourseId. get ( i) ;
System . out. println ( ( i+ 1 ) + " 楼 【" + courseComment. getUserName ( ) + "】 说:" +
courseComment. getComment ( ) ) ;
}
}
测试后,若有对应数据,则测试成功
对应的web层项目也添加对应的接口:
List < CourseComment > getCommentsByCourseId ( @Param ( "courseId" ) Integer courseId, @Param ( "offset" )
Integer offset, @Param ( "pagesize" ) Integer pagesize) ;
对应的CommentController类:
@GetMapping ( "comment/getCourseCommentList/{courseId}/{pageIndex}/{pageSize}" )
public List < CourseComment >
getCommentsByCourseId ( @PathVariable ( "courseId" ) Integer courseId,
@PathVariable ( "pageIndex" ) Integer pageIndex,
@PathVariable ( "pageSize" ) Integer pageSize) {
int pagesize = pageSize;
int pageindex = pageIndex;
List < CourseComment > commentsByCourseId =
commentService. getCommentsByCourseId ( courseId, ( pageindex- 1 ) * 20 , pagesize) ;
return commentsByCourseId;
}
留言 点赞,取消赞(这里并没有按照两个访问地址进行操作,我进行了取反使得实现,即只有一个访问地址)
但最好按照下面来,因为是规定的:
一般在表里面,显示0,或者1的解释时,一般0代表否或者说未,1代表是
如是否删除,那么0代表未删除,1代表已删除,等等
在dao层项目里添加对应的接口及其配置文件:
Integer existsFavorite ( @Param ( "cid" ) Integer cid, @Param ( "uid" ) Integer uid) ;
Integer saveCommentFavorite ( @Param ( "comment_id" ) Integer comment_id, @Param ( "user_id" ) Integer
user_id) ;
Integer updateFavoriteStatus ( @Param ( "is_del" ) Integer is_del, @Param ( "comment_id" ) Integer
comment_id, @Param ( "user_id" ) Integer user_id) ;
Integer FavoriteStatus ( @Param ( "comment_id" ) Integer comment_id, @Param ( "user_id" ) Integer
user_id) ;
Integer updateLikeCount ( @Param ( "like_count" ) Integer like_count, @Param ( "comment_id" ) Integer
comment_id) ;
< select id = " existsFavorite" resultType = " Integer" >
select count(*) from course_comment_favorite_record
where comment_id = #{cid} and user_id = #{uid}
</ select>
< insert id = " saveCommentFavorite" >
insert into
`course_comment_favorite_record`(`user_id`,`comment_id`,`is_del`,`create_time`,
`update_time`) values
(#{user_id},#{comment_id},0,sysdate(),sysdate())
</ insert>
< update id = " updateFavoriteStatus" >
update course_comment_favorite_record set is_del = #{is_del} where comment_id = #{comment_id} and
user_id = #{user_id}
</ update>
< select id = " FavoriteStatus" resultType = " Integer" >
select is_del from course_comment_favorite_record
where comment_id = #{comment_id} and user_id = #{user_id}
</ select>
< update id = " updateLikeCount" >
UPDATE course_comment SET like_count = like_count + #{like_count} WHERE id = #{comment_id}
</ update>
在service层项目中添加对应的接口及其实现类:
Integer saveFavorite ( Integer comment_id, Integer user_id) ;
@Override
public Integer saveFavorite ( Integer comment_id, Integer user_id) {
Integer i = courseCommentDao. existsFavorite ( comment_id, user_id) ;
if ( i == 0 ) {
courseCommentDao. saveCommentFavorite ( comment_id, user_id) ;
courseCommentDao. updateLikeCount ( 1 , comment_id) ;
} else {
Integer is_del = courseCommentDao. FavoriteStatus( comment_id, user_id) ;
is_del = ( is_del== 0 ? 1 : 0 ) ;
courseCommentDao. updateFavoriteStatus ( is_del, comment_id, user_id) ;
if ( is_del == 1 ) {
courseCommentDao. updateLikeCount ( - 1 , comment_id) ;
}
if ( is_del == 0 ) {
courseCommentDao. updateLikeCount ( 1 , comment_id) ;
}
}
return comment_id;
}
添加测试方法:
@Test
public void saveFavorite ( ) {
Integer integer = commentService. saveFavorite ( 2 , 123 ) ;
System . out. println ( integer) ;
}
测试后,观察对应数据库的数据的变化,若符合业务条件,则操作成功
由于上面进行多个多个sql语句的操作,那么我们需要添加事务,使得一起操作,否则可能只有某个执行造成数据不合理
我们在对应的方法上加上如下注解:
@Transactional
public Integer saveFavorite ( Integer comment_id, Integer user_id) {
}
这时我们就操作了事务(前面的配置文件里有对应的配置)
假设我们不使用事务来进行操作,那么我们基本只能给出提示,虽然并没有解决,比如说如下:
public Integer saveFavorite ( Integer comment_id, Integer user_id) {
Integer i = courseCommentDao. existsFavorite ( comment_id, user_id) ;
int i1 = 0 ;
int i2 = 0 ;
if ( i == 0 ) {
i1 = courseCommentDao. saveCommentFavorite ( comment_id, user_id) ;
i2 = courseCommentDao. updateLikeCount ( 1 , comment_id) ;
} else {
Integer is_del = courseCommentDao. FavoriteStatus( comment_id, user_id) ;
is_del = ( is_del== 0 ? 1 : 0 ) ;
i1 = courseCommentDao. updateFavoriteStatus ( is_del, comment_id, user_id) ;
if ( is_del == 1 ) {
i2 = courseCommentDao. updateLikeCount ( - 1 , comment_id) ;
}
if ( is_del == 0 ) {
i2 = courseCommentDao. updateLikeCount ( 1 , comment_id) ;
}
}
if ( i1 == 0 || i2 == 0 ) {
throw new RuntimeException ( "点赞失败" ) ;
}
return comment_id;
}
根据上面的解释,为了全方位的进行好的优化,可以事务与判断提示一起操作,对应的方法修改成如下:
@Override
@Transactional
public Integer saveFavorite ( Integer comment_id, Integer user_id) {
Integer i = courseCommentDao. existsFavorite ( comment_id, user_id) ;
int i1 = 0 ;
int i2 = 0 ;
if ( i == 0 ) {
i1 = courseCommentDao. saveCommentFavorite ( comment_id, user_id) ;
i2 = courseCommentDao. updateLikeCount ( 1 , comment_id) ;
} else {
Integer is_del = courseCommentDao. FavoriteStatus( comment_id, user_id) ;
is_del = ( is_del== 0 ? 1 : 0 ) ;
i1 = courseCommentDao. updateFavoriteStatus ( is_del, comment_id, user_id) ;
if ( is_del == 1 ) {
i2 = courseCommentDao. updateLikeCount ( - 1 , comment_id) ;
}
if ( is_del == 0 ) {
i2 = courseCommentDao. updateLikeCount ( 1 , comment_id) ;
}
}
if ( i1 == 0 || i2 == 0 ) {
throw new RuntimeException ( "点赞失败" ) ;
}
return comment_id;
}
再次进行测试,若数据正确,那么测试成功
实际上这里对应的取消赞和点赞是一起操作的,实际上虽然可以分开,但并不需要,只要取反即可
当然你也可以进行分开操作,只是有点麻烦而已(多加一个service层方法)
对应的web层项目中添加对应的接口:
Integer saveFavorite ( Integer comment_id, Integer user_id) ;
添加对应的CommentController类的部分方法:
@GetMapping ( "comment/Favorite/{commentid}/{userid}" )
public Integer Favorite ( @PathVariable ( "commentid" ) Integer
commentid, @PathVariable ( "userid" ) Integer userid) {
Integer integer = commentService. saveFavorite ( commentid, userid) ;
return integer;
}
启动测试,若对应数据库的数据的确正确,那么操作成功,但这里可能会出现问题,看如下解释
消费方进行远程调用时,服务方需要有对应的方法,否则会报错,但在这个前提下,对应的路径,也就是包的路径需要一致
正是因为这样,所有我们使用对应的@Transactional注解时,由于是默认操作JDK代理
那么当前的类可能会进行改变(对于dubbo的@Service注解来说)
那么对应的@Service注解会使得目标有问题,即对应的接口可能不是操作我们的接口,即路径不同了
那么由于消费方的路径不匹配,那么一般会出现空指针异常
虽然dubbo不操作JDK代理,但是dubbo一般可以操作cglib代理,但前提是,需要对应的@Service注解指定对应的接口
添加部分spring-dao.xml:
< tx: annotation-driven transaction-manager = " transactionManager" proxy-target-class = " true" />
修改对应的CommentServiceImpl类(即CommentService的实现类):
@Service ( interfaceClass = CommentService . class )
public class CommentServiceImpl implements CommentService {
}
到此,再次启动,若返回数据,则基本成功
现在我们来操作对应的个人资料的修改
之前我们进行了用户注册,但一般情况下,我们是需要有头像的,且可以修改名称
为了实现这样的功能,我们需要加上fastdfs对应的依赖,使得保存对应的头像(图片)
< dependency>
< groupId> net.oschina.zcx7878</ groupId>
< artifactId> fastdfs-client-java</ artifactId>
< version> 1.27.0.0</ version>
</ dependency>
< dependency>
< groupId> org.apache.commons</ groupId>
< artifactId> commons-io</ artifactId>
< version> 1.3.2</ version>
</ dependency>
在dao层项目下,加上对应的配置,添加config包,然后创建fastdfs-client.properties:
##fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
#记得改成自己的端口,实际上可以说是去tracker里获得好的storage组的服务器地址
fastdfs.tracker_servers = 192.168.164.128:22122
在对应的测试类里(user包下的那个),添加如下代码:
@Test
public void updateUserInfo ( ) {
try {
ClientGlobal . initByProperties ( "config/fastdfs-client.properties" ) ;
TrackerClient trackerClient = new TrackerClient ( ) ;
TrackerServer trackerServer = trackerClient. getConnection ( ) ;
StorageServer storageServer = null ;
StorageClient1 client1 = new StorageClient1 ( trackerServer, storageServer) ;
NameValuePair [ ] list = new NameValuePair [ 1 ] ;
list[ 0 ] = new NameValuePair ( "fileName" , "1.jpg" ) ;
String fileID = client1. upload_file1 ( "E:\\img\\back.jpg" , "png" , list) ;
System . out. println ( fileID) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
然后取对应的fastdfs服务器查看是否有文件,若要,则保存成功(具体的fastdfs配置看82章博客)
然后进行下载,再次添加对应的测试方法:
@Test
public void DownloadUserInfo ( ) {
try {
ClientGlobal . initByProperties ( "config/fastdfs-client.properties" ) ;
TrackerClient trackerClient = new TrackerClient ( ) ;
TrackerServer trackerServer = trackerClient. getConnection ( ) ;
StorageServer storageServer = null ;
StorageClient1 client1 = new StorageClient1 ( trackerServer, storageServer) ;
byte [ ] bytes = client1. download_file1 ( "group1/ M00 / 00 / 00 / wKikgGLTzP-
AYBaqAANjV8eqsnI531 . png") ;
FileOutputStream fileOutputStream = new FileOutputStream ( new File ( "E:/xxxxxx.jpg" ) ) ;
fileOutputStream. write ( bytes) ;
fileOutputStream. close ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
执行后,看看自己的路径是否有该文件,有,则表示可以下载,也更加的表示前面的保存文件成功
测试完成后,接下来我们在dao层的项目的UserDao接口添加对应的接口及其配置文件:
Integer updateUserInfo ( @Param ( "name" ) String name, @Param ( "portrait" ) String portrait,
@Param ( "uid" ) String uid) ;
< update id = " updateUserInfo" >
UPDATE user SET NAME = #{name} ,portrait = #{portrait} WHERE id = #{uid}
</ update>
对应的service层的接口及其实现类:
Integer updateUserInfo ( String name, String portrait, String uid) ;
@Override
public Integer updateUserInfo ( String name, String portrait, String uid) {
Integer integer = userDao. updateUserInfo ( name, portrait, uid) ;
return integer;
}
对应的web层项目:
在这之前添加对应的依赖:
< dependency>
< groupId> javax.servlet</ groupId>
< artifactId> servlet-api</ artifactId>
< scope> provided</ scope>
< version> 2.5</ version>
</ dependency>
< dependency>
< groupId> commons-fileupload</ groupId>
< artifactId> commons-fileupload</ artifactId>
< version> 1.3.3</ version>
</ dependency>
添加部分spring-consumer.xml:
< bean id = " multipartResolver"
class = " org.springframework.web.multipart.commons.CommonsMultipartResolver" >
< property name = " maxUploadSize" value = " 2048000000" />
</ bean>
对应的接口:
Integer updateUserInfo ( String name, String portrait, String uid) ;
在lagou包下,创建entity包,并创建UserVo类:
package com. lagou. entity ;
public class UserVo {
private String success;
private String state;
private String message;
private Object Vo ;
@Override
public String toString ( ) {
return "UserVo{" +
"success='" + success + '\'' +
", state='" + state + '\'' +
", message='" + message + '\'' +
", Vo=" + Vo +
'}' ;
}
public UserVo ( ) {
}
public UserVo ( String success, String state, String message, Object vo) {
this . success = success;
this . state = state;
this . message = message;
Vo = vo;
}
public String getSuccess ( ) {
return success;
}
public void setSuccess ( String success) {
this . success = success;
}
public String getState ( ) {
return state;
}
public void setState ( String state) {
this . state = state;
}
public String getMessage ( ) {
return message;
}
public void setMessage ( String message) {
this . message = message;
}
public Object getVo ( ) {
return Vo ;
}
public void setVo ( Object vo) {
Vo = vo;
}
}
添加部分UserController类:
@PostMapping ( "updateUserInfo" )
public UserVo updateUserInfo ( MultipartHttpServletRequest request) {
Integer ss = null ;
try {
MultipartFile name = request. getFile ( "portrait" ) ;
String originalFilename = name. getOriginalFilename ( ) ;
String substring = originalFilename. substring ( originalFilename. indexOf ( "." ) + 1 ) ;
String UUID = java. util. UUID . randomUUID ( ) . toString ( ) + "." + substring;
File file = new File ( "E:/upload/" + UUID ) ;
name. transferTo ( file) ;
String absolutePath = file. getAbsolutePath ( ) ;
ClientGlobal . initByProperties ( "config/fastdfs-client.properties" ) ;
TrackerClient trackerClient = new TrackerClient ( ) ;
TrackerServer trackerServer = trackerClient. getConnection ( ) ;
StorageServer storageServer = null ;
StorageClient1 client1 = new StorageClient1 ( trackerServer, storageServer) ;
NameValuePair [ ] list = new NameValuePair [ 1 ] ;
list[ 0 ] = new NameValuePair ( "fileName" , originalFilename) ;
String fileID = client1. upload_file1 ( absolutePath, substring, list) ;
String name1 = request. getParameter ( "name" ) ;
String userid = request. getParameter ( "userid" ) ;
ss = userService. updateUserInfo ( name1, fileID, userid) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
if ( ss!= 0 ) {
return new UserVo ( "true" , "200" , "修改成功" , ss) ;
} else {
return new UserVo ( "true" , "200" , "修改失败" , ss) ;
}
}
在对应的index.jsp代码中添加如下代码:
<form action="/user/updateUserInfo" method="post" enctype="multipart/form-data">
文件:<input type="file" name="portrait"><br>
昵称:<input type="text" name="name"><br>
用户id:<input type="text" name="userid"><br>
<button>提交</button>
</form>
启动测试,若本地以及fastdfs都有对应的文件,那么操作成功
然后去访问对应自己配置好的fastdfs服务器,比如我这里就是
http://192.168.164.128/group1/M00/00/00/wKikgGLVAiyAe_bPAAA50D1yhyo358.png
group1/M00/00/00/wKikgGLVAiyAe_bPAAA50D1yhyo358.png是对应图片在服务器的地址,也就是文件特殊id
对应的用户信息修改成功,这里主要是昵称和头像,接下来我们操作修改密码
对应的dao层项目的接口及其配置文件:
Integer updatePassword ( @Param ( "password" ) String password, @Param ( "uid" ) String uid) ;
< update id = " updatePassword" >
UPDATE user SET PASSWORD = #{password} WHERE id = #{uid}
</ update>
对应的service层项目的接口及其实现类:
Integer updatePassword ( String password, String uid) ;
@Override
public Integer updatePassword ( String password, String uid) {
Integer integer = userDao. updatePassword ( password, uid) ;
return integer;
}
测试类TestUser的部分方法:
@Test
public void updatePassword ( ) {
Integer integer = userService. updatePassword ( "2" , "100030018" ) ;
System . out. println ( integer) ;
}
测试完后,进行下来的操作
web层项目的接口(UserService接口的部分方法):
Integer updatePassword ( String password, String uid) ;
UserController类的部分方法:
@GetMapping ( "updatePassword" )
public UserVo updatePassword ( String password, String uid) {
Integer integer = userService. updatePassword ( password, uid) ;
if ( integer!= 0 ) {
return new UserVo ( "true" , "200" , "修改成功" , integer) ;
} else {
return new UserVo ( "true" , "200" , "修改失败" , integer) ;
}
}
测试后,若修改成功,则操作完成
最后,我们也可以进行根据用户id进行查询用户,虽然我们并不需要,但在有些时候可能会用到
所有后面的代码可以不做考虑:
对应的dao层项目的接口及其配置文件:
User SelectUserById ( String uid) ;
< select id = " SelectUserById" resultMap = " UserMap" >
select * from user where id = #{uid}
</ select>
对应的service代码:
User SelectUserById ( String uid) ;
@Override
public User SelectUserById ( String uid) {
User user = userDao. SelectUserById( uid) ;
return user;
}
部分测试类:
@Test
public void SelectUserById ( ) {
User user = userService. SelectUserById( "100030018" ) ;
System . out. println ( user) ;
}
测试完后,进行下面的操作
对应的web层项目的接口:
User SelectUserById ( String uid) ;
UserController类的部分方法:
@GetMapping ( "SelectUserById" )
public UserVo SelectUserById ( String uid) {
User user = userService. SelectUserById( uid) ;
return new UserVo ( "true" , "200" , "查询成功" , user) ;
}
至此,后端接口编写完毕