基于javaweb的SpringBoot在线学习系统(java+springboot+mybatis+vue+mysql+maven+redis)

运行环境

Java≥8、MySQL≥5.7、Node.js≥14

开发工具

后端:eclipse/idea/myeclipse/sts等均可配置运行
前端:WebStorm/VSCode/HBuilderX等均可

❗没学过node.js的不要搞前后端分离项目

适用

课程设计,大作业,毕业设计,项目练习,学习演示等

功能说明

480023572402

490023572402

500023572402

510023572402

520023572402

530023572402

基于javaweb的SpringBoot在线学习系统(java+springboot+mybatis+vue+mysql+maven+redis)

一、项目运行 环境配置:

Jdk1.8 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。

项目技术:

Spring + SpringBoot+ mybatis + Maven + Vue 等等组成,B/S模式 + Maven管理等等。  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    @Resource
private FavoriteService favoriteService;

@Resource
private HostHolder hostHolder;

/**
* 添加或取消收藏,传个课程id即可,用户id从后台获取
*/
@GetMapping("/change")
public String addFavorite(Integer subjectId) {
Map<String, Object> res = favoriteService.changeFavorite(subjectId, hostHolder.getUser().getId());
return SystemUtil.getJSONString((Integer) res.get("code"), (String) res.get("msg"));
}

/**
* 删除收藏
*/
@DeleteMapping("/delete/{id}")
public String delFavorite(@PathVariable("id") Integer id) {
boolean isOk = favoriteService.delFavoriteById(id);
int code = isOk ? 200 : 2300;
String msg = isOk ? "删除成功!" : "删除失败!";
return SystemUtil.getJSONString(code, msg);
}

/**
* 分页查询出当前登录用户的收藏,当前登录的用户 uid 从 HostHolder 中取,可有模糊搜索共用一个接口
*/
@GetMapping("/all")
public String getPageOfFavorite(Integer pageIndex, String searchContent) {
Integer uid = hostHolder.getUser().getId();
List<PageOfFavoriteResultVO> voList = favoriteService.pageOfFavoriteByUidOrTitle(uid, pageIndex, searchContent);
int total = favoriteService.getCountOfFavoriteByUidOrTitle(uid, searchContent);
return SystemUtil.getJSONString(200, "", new HashMap<String, Object>() {{
put("total", total);
put("favoriteList", voList);
}});
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        int code = isOk ? 200 : 2400;
String msg = isOk ? "删除成功!" : "删除失败!";
return SystemUtil.getJSONString(code, msg);
}
}

package com.gll.onlinelearning.controller;



@RestController
public class LoginController {

private static final Logger logger = LoggerFactory.getLogger(LoginController.class);

@Autowired
private Producer kaptchaProducer;

@Resource
private UserService userService;

@Resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        log.info("LoginTicketInterceptor -> preHandle,url:" + request.getServletPath());
// 从 cookie 中获取凭证
String ticket = CookieUtil.getValue(request, "ticket");
if (ticket != null) {
// 查询凭证
LoginTicket loginTicket = userService.findLoginTicket(ticket);
// 检查凭证是否有效
if (loginTicket != null && loginTicket.getStatus() == 0 && loginTicket.getExpired().after(new Date())) {
User user = userService.getUserById(loginTicket.getUserId());
// 在本次请求中持有用户,将用户暂存到某个线程中
hostHolder.setUser(user);
log.info("LoginTicketInterceptor -> preHandle,loginTicket:" + loginTicket);
return true;
}
}
ResponseUtil.out(response, new JSONObject() {{
put("code", 2000);
put("msg", "你还没有登录哦!");
}});
return false;
}

// 在 controller 之后,模板之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}

/**
* 调用前提:preHandle 返回 true
* 调用时间:DispatcherServlet 进行视图的渲染之后
* 作用:多用于清理资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
hostHolder.clear();
}
}
package com.gll.onlinelearning.aspect;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
        fileDir.mkdirs();
}
// 确定文件存放的路径
File dest = new File(fileDir.getAbsolutePath() + "/" + newFileName);
try {
// 存储文件
file.transferTo(dest);
} catch (IOException e) {
logger.error("上传图片失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
// 更新当前用户的头像的路径(web访问路径)
// http://localhost:8006/user/header/xxx.png
User user = hostHolder.getUser();
String headerUrl = domain + "/user/header/" + newFileName;
userService.updateHeader(user.getId(), headerUrl);
return SystemUtil.getJSONString(200, "上传成功!", new HashMap<String, Object>() {{
put("imgUrl", headerUrl);
}});
}

/**
* 获取用户头像
*/
@GetMapping("/header/{fileName}")
public void getUserHeader(@PathVariable("fileName") String fileName, HttpServletResponse response) {
// 服务器存放路径
fileName = imgUploadPath + "/" + fileName;
// 文件后缀
String suffix = fileName.substring(fileName.lastIndexOf("."));
// 响应图片
response.setContentType("image/" + suffix);
try (
// java 7 写在这里会自动添加finally代码块来关闭流
FileInputStream fis = new FileInputStream(fileName);
OutputStream os = response.getOutputStream()
) {
byte[] buffer = new byte[1024];
int b = 0;
while ((b = fis.read(buffer)) != -1) {
os.write(buffer, 0, b);
}
} catch (IOException e) {
logger.error("读取头像失败: " + e.getMessage());
}
}

/**
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48




public class HttpIpUtils {

/**
* 真实ip地址
*/
public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = ip.indexOf(",");
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
}
ip = request.getHeader("X-Real-IP");
if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
return ip;
}
return request.getRemoteAddr();
}

/**
* 获取用户真实IP地址,不使用request.getRemoteAddr(); 的原因是有可能用户使用了代理软件方式避免真实IP地址
*/
public static String getRealClientIp(HttpServletRequest request) {
String ip;
try {
ip = request.getHeader("x-forwarded-for");
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}

if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}

if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}

if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
                User user = userService.getUserById(loginTicket.getUserId());
// 在本次请求中持有用户,将用户暂存到某个线程中
hostHolder.setUser(user);
log.info("LoginTicketInterceptor -> preHandle,loginTicket:" + loginTicket);
return true;
}
}
ResponseUtil.out(response, new JSONObject() {{
put("code", 2000);
put("msg", "你还没有登录哦!");
}});
return false;
}

// 在 controller 之后,模板之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}

/**
* 调用前提:preHandle 返回 true
* 调用时间:DispatcherServlet 进行视图的渲染之后
* 作用:多用于清理资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
hostHolder.clear();
}
}
package com.gll.onlinelearning.aspect;



//日志切面
@Slf4j
@Aspect


项目链接:
https://javayms.github.io?id=261122572008200tj
https://javayms.pages.dev?id=261122572008200tj