基于javaweb+mysql的springboot在线学习系统(java+springboot+mybatis+vue+mysql+redis)
运行环境
Java≥8、MySQL≥5.7、Node.js≥10
开发工具
后端:eclipse/idea/myeclipse/sts等均可配置运行
前端:WebStorm/VSCode/HBuilderX等均可
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb+mysql的SpringBoot在线学习系统(java+springboot+mybatis+vue+mysql+redis)
一、项目运行 环境配置:
Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。
项目技术:
Spring + SpringBoot+ mybatis + Maven + Vue 等等组成,B/S模式 + Maven管理等等。
* 添加或取消收藏,传个课程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);
}});
}
}
package com.gll.onlinelearning.common;
// 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());
}
}
/**
* 发表帖子,传来2个字段:content 和 pictures(非必须,因为我这边给了默认值)
*/
@PostMapping("/add")
public String addPost(@RequestBody Post post) {
User user = hostHolder.getUser();
post.setUid(user.getId());
boolean isOk = postService.save(post);
int code = isOk ? 200 : 2300;
String msg = isOk ? "发表成功!" : "发表失败!";
return SystemUtil.getJSONString(code, msg);
}
/**
* 分页获取帖子列表,按照更新时间倒叙排,只需要传页码,搜索字段非必须
*/
@GetMapping("/all")
public String getPageOfPost(Integer pageIndex, String searchContent) {
List<PageOfPostResultVO> list = postService.getPageOfPost(pageIndex, searchContent);
int total = postService.getCountOfPostByContent(searchContent);
return SystemUtil.getJSONString(200, "", new HashMap<String, Object>() {{
put("total", total);
put("postList", list);
}});
}
/**
* 获取某条帖子的信息,只需要传帖子 id
*/
@GetMapping("/get/{id}")
public String getPostById(@PathVariable("id") Integer id) {
Post post = postService.getById(id);
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");
}
if ((ip == null) || (ip.length() == 0) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if ("127.0.0.1".equals(ip)) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
assert inet != null;
ip = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
// / "***.***.***.***".length()
if (ip != null && ip.length() > 15) {
// = 15
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
} catch (Exception e) {
@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);
}});
}
}
package com.gll.onlinelearning.common;
//全局异常处理
@ControllerAdvice
@RestController
public class CommonAdvice {
private static Logger logger = LoggerFactory.getLogger(CommonAdvice.class);
/**
* 原始异常处理
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
String handleExceptionForErrorOne(Exception e, HttpServletRequest request) {
logger.info("Exception message:{}", e.getMessage());
logger.info("Exception from:{}", e.getCause());
logger.info("Exception print:{}", e);
return SystemUtil.getJSONString(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
}
/**
* 自定义全局异常处理
*/
@ExceptionHandler(GlobalException.class)
String handleExceptionForErrorTwo(GlobalException e, HttpServletRequest request) {
logger.info("MyException message:{}", e.getMessage());
logger.info("MyException from:{}", e.getCause());
logger.info("MyException print:{}", e);
return SystemUtil.getJSONString(e.getCode(), e.getMessage());
}
}
/**
* 获取验证码
*/
@GetMapping("/kaptcha")
public void getKaptcha(HttpServletResponse response) {
// 生成验证码(文本)
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 验证码的归属
String kaptchaOwner = SystemUtil.generateUUID();
Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
// 验证码有效时间为 60 s
cookie.setMaxAge(60);
// 整个项目都有效
cookie.setPath("/");
// 发送给客户端
response.addCookie(cookie);
// 将验证码存入Redis
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
// redis 有效时间为 60s
redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);
// 将图片输出给浏览器
response.setContentType("image/png");
try {
OutputStream os = response.getOutputStream();
ImageIO.write(image, "png", os);
} catch (IOException e) {
logger.error("响应验证码失败:" + e.getMessage());
}
}
/**
* 登录
*/
@PostMapping("/login")
public String login(String username, String password, String code, boolean rememberme, HttpServletResponse response,
@CookieValue("kaptchaOwner") String kaptchaOwner) {
// kaptchaOwner 为 uuid
// code 为验证码
// 检查验证码
String kaptcha = null;
// 若客户端传来的 cookie 没有失效,则从 redis 中取验证码
if (StringUtils.isNotBlank(kaptchaOwner)) {
// 验证码的 key 为 uuid, 值为 验证码
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
}
if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
boolean isOk = commentService.save(comment);
//重新查询一下插入的评论信息
Comment one = isOk ? commentService.getById(comment.getId()) : null;
if (isOk) {
//查询成功才往 post 表更新 replynum 字段
postService.updateReplynumOfPost(1, comment.getPostId());
return SystemUtil.getJSONString(200, "评论成功!", new HashMap<String, Object>() {{
put("comment", one);
}});
}
return SystemUtil.getJSONString(4000, "评论失败!");
}
/**
* todo:暂时不做这个功能
* 传评论 id 和 评论层级 level
* 删除评论,传一个参数,评论id,还要对其子评论进行递归删除
* 分情况讨论
* ①若 level 为0,则直接删除 id 为 id的那条评论 和 parentId 为 id 的所有记录
* ②若 level 为1,则拿出那条记录的 parentId,然后查出 parentId+(level=2)+(targetId=待删除level=1的评论的那个uid)
* 另外加上直接删除该条评论
* ③若 level 为2,则直接删除 id 为 id的那条评论
* ④减去该帖子被删除的回复数
*/
@PostMapping("/del/{id}")
public String delComment(@PathVariable("id") Integer id) {
boolean isOk = commentService.removeById(id);
int code = isOk ? 200 : 2300;
String msg = isOk ? "删除成功!" : "删除失败!";
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
int code = isOk ? 200 : 2300;
String msg = isOk ? "删除帖子成功!" : "删除帖子失败!";
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
/**
*/
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private final static List<String> imgExtends = Arrays.asList(".jpg", ".png", ".jpeg", ".gif");
int expiredSeconds = rememberme ? SystemConstant.REMEMBER_EXPIRED_SECONDS : SystemConstant.DEFAULT_EXPIRED_SECONDS;
Map<String, Object> map = userService.login(username, password, expiredSeconds);
Map<String, Object> res = new HashMap<>();
if (map.containsKey("ticket")) {
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
// cookie设置整个项目访问路径都有效
cookie.setPath("/");
cookie.setMaxAge(expiredSeconds);
cookie.setHttpOnly(false);
response.addCookie(cookie);
res.put("userInfo", map.get("userInfo"));
return SystemUtil.getJSONString(200, "登录成功!", res);
} else {
return SystemUtil.getJSONString(2011, (String) map.get("errMsg"));
}
}
/**
* 用户注册
*/
@PostMapping("/register")
public String register(@RequestBody User user) {
Map<String, Object> map = userService.register(user);
if (map.isEmpty()) {
return SystemUtil.getJSONString(200, "注册成功");
} else {
return SystemUtil.getJSONString(2008, (String) map.get("errMsg"));
}
}
/**
* 登出
*/
@GetMapping("/logout")
public void logout(@CookieValue("ticket") String ticket) {
userService.logout(ticket);
}
}
package com.gll.onlinelearning.utils;
put("subjectList", subjectList);
}});
}
/**
* 读取 execl 数据并插入到数据库中
*/
@PostMapping("/add")
public String addSubject(MultipartFile file) {
subjectService.saveSubject(file, subjectService);
return SystemUtil.getJSONString(200, "上传成功!");
}
}
package com.gll.onlinelearning.controller;
/**
*/
@RestController
@RequestMapping("/love")
public class LoveController {
@Resource
private HostHolder hostHolder;
@Resource
private LoveService loveService;
/**
* 点赞 或 取消点赞,只需要传 帖子id,当前操作人id 直接从 hostHolder 中取即可
*/
@GetMapping("/change")
public String changeLove(Integer postId) {
Integer uid = hostHolder.getUser().getId();
Map<String, Object> res = loveService.changeLove(postId, uid);
int code = isOk ? 200 : 2300;
String msg = isOk ? "更新成功!" : "更新失败!";
return SystemUtil.getJSONString(code, msg);
}
/**
* 删除帖子,当前用户为登录的用户
*/
@DeleteMapping("/del/{id}")
public String delPost(@PathVariable("id") Integer id) {
boolean isOk = postService.delPostById(id);
int code = isOk ? 200 : 2300;
String msg = isOk ? "删除帖子成功!" : "删除帖子失败!";
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
/**
*/
@RestController
@RequestMapping("/user")
@Slf4j
public class LoginTicketInterceptor implements HandlerInterceptor {
@Resource
private UserService userService;
@Resource
private HostHolder hostHolder;
/**
* 调用时间:Controller方法处理之前
* 执行顺序:链式 Interceptor 情况下,Interceptor 按照声明的顺序一个接一个执行
* 若返回 false,则中断执行,注意:不会进入 afterCompletion
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
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", "你还没有登录哦!");
// 在 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
@Component
public class SysLogAspect {
@Pointcut("execution(* com.gll.onlinelearning.controller..*.*(..))")
public void log() {
}
private final static List<String> imgExtends = Arrays.asList(".jpg", ".png", ".jpeg", ".gif");
@Value("${onlinelearning.path.upload.img}")
private String imgUploadPath;
@Value("${onlinelearning.path.domain}")
private String domain;
@Resource
private PostService postService;
@Resource
private HostHolder hostHolder;
@Resource
private UserService userService;
/**
* 上传图片
*/
@PostMapping("/imgUpload")
public String uploadHeader(MultipartFile file) {
String fileName;
if (file == null || (fileName = file.getOriginalFilename()) == null) {
return SystemUtil.getJSONString(2013, "您还没有选择图片!");
}
String suffix = fileName.substring(fileName.lastIndexOf("."));
if (StringUtils.isBlank(suffix) || !imgExtends.contains(suffix.toLowerCase())) {
return SystemUtil.getJSONString(2013, "图片格式不正确!");
}
// 生成随机文件名
String newFileName = SystemUtil.generateUUID() + suffix;
// 构建上传文件的存放 "文件夹" 路径
File fileDir = new File(imgUploadPath);
if (!fileDir.exists()) {
// 递归生成文件夹
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/post/imgLoader/xxx.png
*/
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
private final static List<String> imgExtends = Arrays.asList(".jpg", ".png", ".jpeg", ".gif");
@Value("${onlinelearning.path.upload.img}")
private String imgUploadPath;
@Value("${onlinelearning.path.domain}")
private String domain;
@Resource
private HostHolder hostHolder;
@Resource
private UserService userService;
/**
* 更新头像
*/
@PostMapping("/updateAvatar")
public String uploadHeader(MultipartFile file) {
String fileName;
if (file == null || (fileName = file.getOriginalFilename()) == null) {
return SystemUtil.getJSONString(2013, "您还没有选择图片!");
}
String suffix = fileName.substring(fileName.lastIndexOf("."));
if (StringUtils.isBlank(suffix) || !imgExtends.contains(suffix.toLowerCase())) {
return SystemUtil.getJSONString(2013, "图片格式不正确!");
}
// 生成随机文件名
String newFileName = SystemUtil.generateUUID() + suffix;
// 构建上传文件的存放 "文件夹" 路径
File fileDir = new File(imgUploadPath);
if (!fileDir.exists()) {
// 递归生成文件夹
fileDir.mkdirs();
}
// 确定文件存放的路径
File dest = new File(fileDir.getAbsolutePath() + "/" + newFileName);
try {
// 存储文件
file.transferTo(dest);
} catch (IOException e) {
logger.error("上传图片失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 获取验证码
*/
@GetMapping("/kaptcha")
public void getKaptcha(HttpServletResponse response) {
// 生成验证码(文本)
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 验证码的归属
String kaptchaOwner = SystemUtil.generateUUID();
Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
// 验证码有效时间为 60 s
cookie.setMaxAge(60);
// 整个项目都有效
cookie.setPath("/");
// 发送给客户端
response.addCookie(cookie);
// 将验证码存入Redis
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
// redis 有效时间为 60s
redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);
// 将图片输出给浏览器
response.setContentType("image/png");
try {
OutputStream os = response.getOutputStream();
ImageIO.write(image, "png", os);
} catch (IOException e) {
logger.error("响应验证码失败:" + e.getMessage());
}
}
/**
* 登录
*/
@PostMapping("/login")
public String login(String username, String password, String code, boolean rememberme, HttpServletResponse response,
@CookieValue("kaptchaOwner") String kaptchaOwner) {
// kaptchaOwner 为 uuid
// code 为验证码
// 检查验证码
String kaptcha = null;
// 若客户端传来的 cookie 没有失效,则从 redis 中取验证码
if (StringUtils.isNotBlank(kaptchaOwner)) {
// 验证码的 key 为 uuid, 值为 验证码
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
/**
*/
@RestController
@RequestMapping("/love")
public class LoveController {
@Resource
private HostHolder hostHolder;
@Resource
private LoveService loveService;
/**
* 点赞 或 取消点赞,只需要传 帖子id,当前操作人id 直接从 hostHolder 中取即可
*/
@GetMapping("/change")
public String changeLove(Integer postId) {
Integer uid = hostHolder.getUser().getId();
Map<String, Object> res = loveService.changeLove(postId, uid);
return SystemUtil.getJSONString((Integer) res.get("code"), (String) res.get("msg"), new HashMap<String, Object>() {{
put("resLove", res.get("resLove"));
}});
}
}
package com.gll.onlinelearning.filter;
//跨域处理
@Configuration
public class MyCorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
/**
*/
@RestController
@RequestMapping("/favorite")
public class FavoriteController {
@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);
}
/**
* 删除评论,传一个参数,评论id,还要对其子评论进行递归删除
* 分情况讨论
* ①若 level 为0,则直接删除 id 为 id的那条评论 和 parentId 为 id 的所有记录
* ②若 level 为1,则拿出那条记录的 parentId,然后查出 parentId+(level=2)+(targetId=待删除level=1的评论的那个uid)
* 另外加上直接删除该条评论
* ③若 level 为2,则直接删除 id 为 id的那条评论
* ④减去该帖子被删除的回复数
*/
@PostMapping("/del/{id}")
public String delComment(@PathVariable("id") Integer id) {
boolean isOk = commentService.removeById(id);
int code = isOk ? 200 : 2300;
String msg = isOk ? "删除成功!" : "删除失败!";
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
/**
*/
@RestController
@RequestMapping("/favorite")
public class FavoriteController {
@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"));
}
resp.setContentType("application/octet-stream"); //告诉浏览器输出内容为流
resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
byte[] buffer = new byte[1024];
int b = 0;
while ((b = fis.read(buffer)) != -1) {
os.write(buffer, 0, b);
}
} catch (Exception e) {
logger.error("读取文件失败: " + e.getMessage());
}
}
/**
* 删除笔记
*/
@DeleteMapping("/delete/{id}")
public String delNote(@PathVariable("id") Integer id) {
boolean isOk = noteService.removeById(id);
int code = isOk ? 200 : 2400;
String msg = isOk ? "删除成功!" : "删除失败!";
return SystemUtil.getJSONString(code, msg);
}
}
package com.gll.onlinelearning.controller;
* 上传笔记
*/
@PostMapping("/add")
public String uploadHeader(MultipartFile file) {
String fileName;
if (file == null || (fileName = file.getOriginalFilename()) == null) {
return SystemUtil.getJSONString(2013, "您还没有选择文件!");
}
String suffix = fileName.substring(fileName.lastIndexOf("."));
if (StringUtils.isBlank(suffix)) {
return SystemUtil.getJSONString(2013, "文件格式不正确!");
}
// 生成随机文件名
String newFileName = SystemUtil.generateUUID() + suffix;
// 构建上传文件的存放 "文件夹" 路径
File fileDir = new File(fileUploadPath);
if (!fileDir.exists()) {
// 递归生成文件夹
fileDir.mkdirs();
}
// 确定文件存放的路径
File dest = new File(fileDir.getAbsolutePath() + "/" + newFileName);
try {
// 存储文件
file.transferTo(dest);
} catch (IOException e) {
logger.error("上传文件失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
// 笔记下载路径
// http://localhost:8006/note/download/xxxxx.pdf
User user = hostHolder.getUser();
String downloadUrl = domain + "/note/download/" + newFileName;
Note note = new Note();
note.setUid(user.getId());
note.setUsername(user.getUsername());
note.setFilename(fileName);
note.setDownloadUrl(downloadUrl);
noteService.save(note);
return SystemUtil.getJSONString(200, "上传成功!");
}
package com.gll.onlinelearning.utils;
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");
}
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
@Component
public class SysLogAspect {
@Pointcut("execution(* com.gll.onlinelearning.controller..*.*(..))")
public void log() {
} else {
return SystemUtil.getJSONString(2008, (String) map.get("errMsg"));
}
}
/**
* 登出
*/
@GetMapping("/logout")
public void logout(@CookieValue("ticket") String ticket) {
userService.logout(ticket);
}
}
package com.gll.onlinelearning.utils;
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");
//日志切面
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Pointcut("execution(* com.gll.onlinelearning.controller..*.*(..))")
public void log() {
}
@Before("log()")
public void doBefore(JoinPoint joinPoint) throws UnsupportedEncodingException {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String method = request.getMethod();
StringBuffer paramsValue = new StringBuffer();
Object paramsName = null;
// get请求
if (HttpMethod.GET.toString().equals(method)) {
String queryString = request.getQueryString();
if (!StringUtils.isEmpty(queryString)) {
paramsName = JSON.parseObject(JSON.toJSONString(joinPoint.getSignature())).get("parameterNames");
paramsValue.append(URLDecoder.decode(queryString, "UTF-8"));
}
} else {
//其他请求
Object[] paramsArray = joinPoint.getArgs();
paramsName = JSON.parseObject(JSON.toJSONString(joinPoint.getSignature())).get("parameterNames");
for (Object o : paramsArray) {
paramsValue.append(o).append(" ");
}
}
String ip = HttpIpUtils.getClientIp(request);
log.info("URLParamName:" + paramsName);
log.info("URLParamValue:" + paramsValue);
log.info("URL:{},HTTP_METHOD:{},IP:{},Method:{}", request.getRequestURL().toString(), request.getMethod(), ip, joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
}
}
package com.gll.onlinelearning.controller;
@Resource
private NoteService noteService;
/**
* 分页查询出所有用户上传的笔记
*/
@GetMapping("/all/{pageIndex}")
public String getPageOfNote(@PathVariable("pageIndex") Integer pageIndex) {
IPage<Note> list = noteService.getPageOfNote(pageIndex);
return SystemUtil.getJSONString(200, "", new HashMap<String, Object>() {{
put("total", list.getTotal());
put("noteList", list.getRecords());
}});
}
/**
* 上传笔记
*/
@PostMapping("/add")
public String uploadHeader(MultipartFile file) {
String fileName;
if (file == null || (fileName = file.getOriginalFilename()) == null) {
return SystemUtil.getJSONString(2013, "您还没有选择文件!");
}
String suffix = fileName.substring(fileName.lastIndexOf("."));
if (StringUtils.isBlank(suffix)) {
return SystemUtil.getJSONString(2013, "文件格式不正确!");
}
// 生成随机文件名
String newFileName = SystemUtil.generateUUID() + suffix;
// 构建上传文件的存放 "文件夹" 路径
File fileDir = new File(fileUploadPath);
if (!fileDir.exists()) {
// 递归生成文件夹
fileDir.mkdirs();
}
// 确定文件存放的路径
File dest = new File(fileDir.getAbsolutePath() + "/" + newFileName);
try {
// 存储文件
file.transferTo(dest);
} catch (IOException e) {
logger.error("上传文件失败: " + e.getMessage());
throw new RuntimeException("上传文件失败,服务器发生异常!", e);
}
// 笔记下载路径
// http://localhost:8006/note/download/xxxxx.pdf
User user = hostHolder.getUser();
String downloadUrl = domain + "/note/download/" + newFileName;
Note note = new Note();
note.setUid(user.getId());