update
avatar upload and fetch function√ Signed-off-by: Chenx221 <chenx221@yandex.com>
This commit is contained in:
parent
0181f98b45
commit
fe8003faf5
@ -21,7 +21,6 @@
|
||||
<element id="library" level="project" name="Maven: com.google.protobuf:protobuf-java:3.11.4" />
|
||||
<element id="library" level="project" name="Maven: com.squareup.okhttp3:okhttp:4.10.0" />
|
||||
<element id="library" level="project" name="Maven: com.squareup.okio:okio-jvm:3.1.0" />
|
||||
<element id="library" level="project" name="Maven: commons-io:commons-io:2.12.0" />
|
||||
<element id="library" level="project" name="Maven: io.minio:minio:8.5.3" />
|
||||
<element id="library" level="project" name="Maven: javax.servlet.jsp:javax.servlet.jsp-api:2.3.3" />
|
||||
<element id="library" level="project" name="Maven: javax.servlet:javax.servlet-api:4.0.1" />
|
||||
@ -60,6 +59,8 @@
|
||||
<element id="library" level="project" name="Maven: org.springframework:spring-webmvc:5.3.27" />
|
||||
<element id="library" level="project" name="Maven: org.xerial.snappy:snappy-java:1.1.8.4" />
|
||||
<element id="library" level="project" name="Maven: taglibs:standard:1.1.2" />
|
||||
<element id="library" level="project" name="Maven: commons-fileupload:commons-fileupload:1.5" />
|
||||
<element id="library" level="project" name="Maven: commons-io:commons-io:2.11.0" />
|
||||
</element>
|
||||
</element>
|
||||
</root>
|
||||
|
@ -3,13 +3,23 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:multipart="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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
|
||||
<!-- 开启注解扫描 -->
|
||||
<context:component-scan base-package="cyou.chenx221"/>
|
||||
|
||||
<bean id="multipartResolver"
|
||||
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
|
||||
|
||||
<!-- one of the properties available; the maximum file size 15M -->
|
||||
<property name="maxUploadSize" value="15728640"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- 配置数据源 -->
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -45,4 +45,14 @@
|
||||
FROM user
|
||||
WHERE username = #{username}
|
||||
</select>
|
||||
<update id="setAvatar" parameterType="cyou.chenx221.pojo.User">
|
||||
UPDATE user
|
||||
SET photo = #{avatar}
|
||||
WHERE username = #{username}
|
||||
</update>
|
||||
<select id="getAvatar" parameterType="String" resultType="String">
|
||||
SELECT photo
|
||||
FROM user
|
||||
WHERE username = #{username}
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -29,6 +29,7 @@
|
||||
<security:intercept-url pattern="/output/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<security:intercept-url pattern="/system/**" access="hasRole('admin')"/>
|
||||
<security:intercept-url pattern="/user/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<security:intercept-url pattern="/person/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<!-- 未登录状态下会自动跳转到/login登录页-->
|
||||
<security:form-login login-page="/login"
|
||||
default-target-url="/dashboard"
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -76,7 +76,7 @@
|
||||
系统管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown4">
|
||||
<li><a class="dropdown-item" href="#">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="/person/settings">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="/system/settings">系统设定</a></li>
|
||||
<li><a class="dropdown-item" href="/user/usermanage">用户管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">日志管理</a></li>
|
||||
|
@ -0,0 +1,252 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
|
||||
<title>个人设置</title>
|
||||
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.0.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700;900&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/mdb.min.css"/>
|
||||
<style>
|
||||
.tab-pane {
|
||||
min-height: 500px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: 'Noto Sans SC Regular',serif">
|
||||
<!--Main Navigation-->
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light" style="z-index: 1;min-height: 58.59px">
|
||||
<div class="container">
|
||||
<button class="navbar-toggler" type="button" data-mdb-toggle="collapse"
|
||||
data-mdb-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<a class="navbar-brand mt-2 mt-lg-0" href="#">
|
||||
<i class="fas fa-chalkboard-user me-2"></i>
|
||||
教务管理系统
|
||||
</a>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">首页</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown1" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
学生管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown1">
|
||||
<li><a class="dropdown-item" href="#">学生信息查询</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生信息管理</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider"/>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider"/>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown2" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
教师管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown2">
|
||||
<li><a class="dropdown-item" href="#">教师信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">教师课程管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown3" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
课程管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown3">
|
||||
<li><a class="dropdown-item" href="#">课程信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">课程安排管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown4" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
系统管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown4">
|
||||
<li><a class="dropdown-item" href="#">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="#">用户管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">日志管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">版本信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle d-flex align-items-center hidden-arrow" href="#"
|
||||
id="navbarDropdownMenuAvatar" role="button" data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-circle-user fa-lg me-1"></i>
|
||||
${username}
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuAvatar">
|
||||
<li>
|
||||
<a class="dropdown-item" href="${pageContext.request.contextPath}/logout">登出</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!--Main Navigation-->
|
||||
|
||||
<!--Main layout-->
|
||||
<main>
|
||||
<div class="bg-image shadow-2-strong vh-100"
|
||||
style="background-image: url('${pageContext.request.contextPath}/resources/img/jason-blackeye-nyL-rzwP-Mk-unsplash.jpg'); margin-top: -58.59px;">
|
||||
<div class="mask d-flex align-items-center h-100" style="background-color: hsla(0, 0%, 100%, 0.5);">
|
||||
<div class="container d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary" onclick="function goBack() {
|
||||
window.history.back(); //返回上一页
|
||||
}
|
||||
goBack()">返回
|
||||
</button>
|
||||
<div class="container">
|
||||
<div class="card rounded-4 shadow-3-strong" style="min-width: 244px">
|
||||
<ul class="nav nav-tabs" id="ex1" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link active fs-6" id="ex1-tab-1" data-mdb-toggle="tab" href="#ex1-tabs-1"
|
||||
role="tab" aria-controls="ex1-tabs-1" aria-selected="true">设置</a>
|
||||
</li>
|
||||
</ul>
|
||||
<hr class="hr" style="margin: 1px"/>
|
||||
<div class="tab-content" id="ex1-content">
|
||||
<div class="tab-pane fade show active" id="ex1-tabs-1" role="tabpanel"
|
||||
aria-labelledby="ex1-tab-1">
|
||||
<div class="card-body" style="min-width: 175px">
|
||||
<form action="save_avatar" method="post">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 text-center">
|
||||
<p>
|
||||
Avatar:
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<i class="far fa-circle-user fa-8x" id="default_avatar"></i>
|
||||
<img src="#" class="img-fluid rounded-circle" alt="avatar"
|
||||
style="height: 128px;width: 128px;display: none"
|
||||
id="custom_avatar"/>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<label class="form-label" for="customFile">请选择要上传的图片</label>
|
||||
<input type="file" class="form-control" id="customFile" name="avatar"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center mt-lg-5">
|
||||
<button type="submit" class="btn btn-secondary btn-lg" onclick="save()">
|
||||
SAVE
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">
|
||||
<i class="fas fa-circle-info me-2"></i>提示
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<c:if test="${not empty message}">
|
||||
${message}
|
||||
</c:if>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-mdb-dismiss="modal">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!--Main layout-->
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-link text-center text-lg-start ">
|
||||
</footer>
|
||||
<!-- Footer -->
|
||||
|
||||
|
||||
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/mdb.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
<c:if test="${not empty message && message ne 'null'}">
|
||||
$('#exampleModal').modal('show');
|
||||
</c:if>
|
||||
|
||||
$('#customFile').on('change', function() {
|
||||
var file = this.files[0]; // 获取选择的文件
|
||||
|
||||
// 检查是否选择了文件
|
||||
if (!file) {
|
||||
// 如果没有选择文件,执行相应的操作
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建FormData对象,将文件数据附加到其中
|
||||
var formData = new FormData();
|
||||
formData.append('avatar', file);
|
||||
|
||||
// 发送AJAX请求到后端的uploadAvatar方法
|
||||
$.ajax({
|
||||
url: 'uploadAvatar',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false, // 告诉jQuery不要处理FormData对象
|
||||
contentType: false, // 告诉jQuery不要设置Content-Type请求头
|
||||
success: function(response) {
|
||||
// 成功上传后的操作
|
||||
$('#default_avatar').hide(); // 隐藏默认头像
|
||||
$('#custom_avatar').attr('src', response.avatarUrl).show(); // 更新自定义头像的图像源
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.log('上传失败:', error);
|
||||
alert('上传失败,请重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -152,7 +152,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.12.0</version>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
@ -170,7 +170,12 @@
|
||||
<artifactId>okio-jvm</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.5</version>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.jetbrains.kotlin</groupId>-->
|
||||
<!-- <artifactId>kotlin-stdlib-common</artifactId>-->
|
||||
<!-- <version>1.6.20</version>-->
|
||||
|
@ -0,0 +1,86 @@
|
||||
package cyou.chenx221.controller;
|
||||
|
||||
import cyou.chenx221.helper.UsernameHelper;
|
||||
import cyou.chenx221.mapper.UserMapper;
|
||||
import cyou.chenx221.pojo.Course;
|
||||
import cyou.chenx221.pojo.User;
|
||||
import cyou.chenx221.service.PersonService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/person")
|
||||
public class PersonController {
|
||||
private final PersonService personService;
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Autowired
|
||||
public PersonController(PersonService personService) {
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
@GetMapping("/settings")//课程信息查询(不带条件)
|
||||
public String getPersonSettings(Model model) {
|
||||
String username = new UsernameHelper().getCurrentUsername();
|
||||
if (username != null) {
|
||||
model.addAttribute("username", username);
|
||||
}
|
||||
return "person"; // 重定向到 dashboard 页面
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping("/uploadAvatar")
|
||||
public ResponseEntity<Map<String, String>> uploadAvatar(@RequestParam("avatar") MultipartFile file) {
|
||||
Map<String, String> response = new HashMap<>();
|
||||
|
||||
// 处理上传的头像图片文件 //TODO: 清理没有关联的图像资源
|
||||
if (!file.isEmpty()) {
|
||||
try {
|
||||
// String avatarUrl = personService.uploadAvatar(file);
|
||||
String object = personService.uploadAvatar(file);
|
||||
User user = new User();
|
||||
user.setUsername(new UsernameHelper().getCurrentUsername());
|
||||
user.setAvatar(object);
|
||||
userMapper.setAvatar(user);
|
||||
// 设置返回的avatarUrl值
|
||||
response.put("avatarUrl", "/person/image");
|
||||
// response.put("avatarUrl", avatarUrl);
|
||||
|
||||
// 返回成功消息和avatarUrl
|
||||
return ResponseEntity.ok(response);
|
||||
} catch (Exception e) {
|
||||
String errorMessage = "Error uploading file: " + e.getMessage();
|
||||
response.put("message", errorMessage);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
|
||||
}
|
||||
} else {
|
||||
response.put("message", "No file received");
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/image")
|
||||
public ResponseEntity<InputStreamResource> getPersonImage() {
|
||||
String objectName = userMapper.getAvatar(new UsernameHelper().getCurrentUsername());
|
||||
try {
|
||||
InputStreamResource imageResource = personService.getImage(objectName);
|
||||
return ResponseEntity.ok().body(imageResource);
|
||||
} catch (Exception e) {
|
||||
// Handle exception and return appropriate response
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -25,4 +25,8 @@ public interface UserMapper {
|
||||
int enabledUser(int id);
|
||||
|
||||
int getDetailByUsername(String username);
|
||||
|
||||
void setAvatar(User user);
|
||||
|
||||
String getAvatar(String username);
|
||||
}
|
||||
|
@ -9,6 +9,16 @@ public class User {
|
||||
private int disabled;//是否被禁用
|
||||
private boolean disabled_str;
|
||||
|
||||
private String avatar;
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public boolean getDisabled_str() {
|
||||
return disabled_str;
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
package cyou.chenx221.service;
|
||||
|
||||
import io.minio.*;
|
||||
import io.minio.errors.MinioException;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class PersonService {
|
||||
|
||||
private static final String MINIO_ENDPOINT = "http://192.168.8.149:9199";
|
||||
private static final String MINIO_ACCESS_KEY = "cGa3QelqYf3Ujw29vR6o";
|
||||
private static final String MINIO_SECRET_KEY = "WzV1WFCovOFcFj31v7tlqDCzeIkM90m8EAunMC7b";
|
||||
private static final String MINIO_BUCKET_NAME = "project2";
|
||||
|
||||
public String uploadAvatar(MultipartFile file) throws IOException {
|
||||
String tempFilePath = "file/" + file.getOriginalFilename();
|
||||
File tempFile = new File(tempFilePath);
|
||||
file.transferTo(tempFile);
|
||||
String objectName = null;
|
||||
try {
|
||||
// Create a MinioClient with the MinIO server endpoint, access key, and secret key.
|
||||
MinioClient minioClient =
|
||||
MinioClient.builder()
|
||||
.endpoint(MINIO_ENDPOINT)
|
||||
.credentials(MINIO_ACCESS_KEY, MINIO_SECRET_KEY)
|
||||
.build();
|
||||
|
||||
// Make bucket if not exist.
|
||||
boolean found =
|
||||
minioClient.bucketExists(BucketExistsArgs.builder().bucket(MINIO_BUCKET_NAME).build());
|
||||
if (!found) {
|
||||
// Make a new bucket called 'project2'.
|
||||
minioClient.makeBucket(MakeBucketArgs.builder().bucket(MINIO_BUCKET_NAME).build());
|
||||
} else {
|
||||
System.out.println("[INFO] Bucket 'project2' already exists.");
|
||||
}
|
||||
|
||||
// Generate a unique object name
|
||||
objectName = generateUniqueObjectName(file.getOriginalFilename());
|
||||
System.out.println("[INFO] Uploading file '" + objectName + "' to bucket '" + MINIO_BUCKET_NAME + "'.");
|
||||
// Upload the file to the bucket
|
||||
minioClient.uploadObject(
|
||||
UploadObjectArgs.builder()
|
||||
.bucket(MINIO_BUCKET_NAME)
|
||||
.object(objectName)
|
||||
.filename(tempFile.getAbsolutePath())
|
||||
// .contentType("image/jpeg")
|
||||
.build());
|
||||
} catch (MinioException e) {
|
||||
System.out.println("Error occurred: " + e);
|
||||
System.out.println("HTTP trace: " + e.httpTrace());
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
tempFile.delete();
|
||||
return objectName;
|
||||
}
|
||||
|
||||
private String generateUniqueObjectName(String originalFilename) {
|
||||
return UUID.randomUUID() + "_" + originalFilename;
|
||||
}
|
||||
|
||||
public InputStreamResource getImage(String object) throws Exception {
|
||||
// Create a MinioClient with the MinIO server endpoint, access key, and secret key.
|
||||
MinioClient minioClient =
|
||||
MinioClient.builder()
|
||||
.endpoint(MINIO_ENDPOINT)
|
||||
.credentials(MINIO_ACCESS_KEY, MINIO_SECRET_KEY)
|
||||
.build();
|
||||
|
||||
// Get the object from MinIO
|
||||
InputStream stream = minioClient.getObject(
|
||||
GetObjectArgs.builder()
|
||||
.bucket(MINIO_BUCKET_NAME)
|
||||
.object(object)
|
||||
.build()
|
||||
);
|
||||
|
||||
// Wrap the image data in InputStreamResource
|
||||
return new InputStreamResource(stream);
|
||||
}
|
||||
|
||||
}
|
@ -3,13 +3,23 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:multipart="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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
|
||||
<!-- 开启注解扫描 -->
|
||||
<context:component-scan base-package="cyou.chenx221"/>
|
||||
|
||||
<bean id="multipartResolver"
|
||||
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
|
||||
|
||||
<!-- one of the properties available; the maximum file size 15M -->
|
||||
<property name="maxUploadSize" value="15728640"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- 配置数据源 -->
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
|
||||
|
@ -45,4 +45,14 @@
|
||||
FROM user
|
||||
WHERE username = #{username}
|
||||
</select>
|
||||
<update id="setAvatar" parameterType="cyou.chenx221.pojo.User">
|
||||
UPDATE user
|
||||
SET photo = #{avatar}
|
||||
WHERE username = #{username}
|
||||
</update>
|
||||
<select id="getAvatar" parameterType="String" resultType="String">
|
||||
SELECT photo
|
||||
FROM user
|
||||
WHERE username = #{username}
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -29,6 +29,7 @@
|
||||
<security:intercept-url pattern="/output/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<security:intercept-url pattern="/system/**" access="hasRole('admin')"/>
|
||||
<security:intercept-url pattern="/user/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<security:intercept-url pattern="/person/**" access="hasAnyRole('admin','teacher')"/>
|
||||
<!-- 未登录状态下会自动跳转到/login登录页-->
|
||||
<security:form-login login-page="/login"
|
||||
default-target-url="/dashboard"
|
||||
|
@ -76,7 +76,7 @@
|
||||
系统管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown4">
|
||||
<li><a class="dropdown-item" href="#">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="/person/settings">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="/system/settings">系统设定</a></li>
|
||||
<li><a class="dropdown-item" href="/user/usermanage">用户管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">日志管理</a></li>
|
||||
|
253
project2/web/WEB-INF/views/person.jsp
Normal file
253
project2/web/WEB-INF/views/person.jsp
Normal file
@ -0,0 +1,253 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
|
||||
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
|
||||
<title>个人设置</title>
|
||||
<script src="${pageContext.request.contextPath}/resources/js/jquery-3.7.0.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700;900&display=swap"
|
||||
rel="stylesheet">
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/mdb.min.css"/>
|
||||
<style>
|
||||
.tab-pane {
|
||||
min-height: 500px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: 'Noto Sans SC Regular',serif">
|
||||
<!--Main Navigation-->
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light" style="z-index: 1;min-height: 58.59px">
|
||||
<div class="container">
|
||||
<button class="navbar-toggler" type="button" data-mdb-toggle="collapse"
|
||||
data-mdb-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<a class="navbar-brand mt-2 mt-lg-0" href="#">
|
||||
<i class="fas fa-chalkboard-user me-2"></i>
|
||||
教务管理系统
|
||||
</a>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="#">首页</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown1" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
学生管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown1">
|
||||
<li><a class="dropdown-item" href="#">学生信息查询</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生信息管理</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider"/>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生成绩管理</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider"/>
|
||||
</li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">学生选课管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown2" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
教师管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown2">
|
||||
<li><a class="dropdown-item" href="#">教师信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">教师课程管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown3" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
课程管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown3">
|
||||
<li><a class="dropdown-item" href="#">课程信息管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">课程安排管理</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown4" role="button"
|
||||
data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
系统管理
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown4">
|
||||
<li><a class="dropdown-item" href="#">个人设定</a></li>
|
||||
<li><a class="dropdown-item" href="#">用户管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">日志管理</a></li>
|
||||
<li><a class="dropdown-item" href="#">版本信息</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle d-flex align-items-center hidden-arrow" href="#"
|
||||
id="navbarDropdownMenuAvatar" role="button" data-mdb-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-circle-user fa-lg me-1"></i>
|
||||
${username}
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuAvatar">
|
||||
<li>
|
||||
<a class="dropdown-item" href="${pageContext.request.contextPath}/logout">登出</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<!--Main Navigation-->
|
||||
|
||||
<!--Main layout-->
|
||||
<main>
|
||||
<div class="bg-image shadow-2-strong vh-100"
|
||||
style="background-image: url('${pageContext.request.contextPath}/resources/img/jason-blackeye-nyL-rzwP-Mk-unsplash.jpg'); margin-top: -58.59px;">
|
||||
<div class="mask d-flex align-items-center h-100" style="background-color: hsla(0, 0%, 100%, 0.5);">
|
||||
<div class="container d-flex justify-content-center">
|
||||
<button type="button" class="btn btn-primary" onclick="function goBack() {
|
||||
window.history.back(); //返回上一页
|
||||
}
|
||||
goBack()">返回
|
||||
</button>
|
||||
<div class="container">
|
||||
<div class="card rounded-4 shadow-3-strong" style="min-width: 244px">
|
||||
<ul class="nav nav-tabs" id="ex1" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link active fs-6" id="ex1-tab-1" data-mdb-toggle="tab" href="#ex1-tabs-1"
|
||||
role="tab" aria-controls="ex1-tabs-1" aria-selected="true">设置</a>
|
||||
</li>
|
||||
</ul>
|
||||
<hr class="hr" style="margin: 1px"/>
|
||||
<div class="tab-content" id="ex1-content">
|
||||
<div class="tab-pane fade show active" id="ex1-tabs-1" role="tabpanel"
|
||||
aria-labelledby="ex1-tab-1">
|
||||
<div class="card-body" style="min-width: 175px">
|
||||
<form action="save_avatar" method="post">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 text-center">
|
||||
<p>
|
||||
Avatar:
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-lg-2">
|
||||
<i class="far fa-circle-user fa-8x" id="default_avatar"></i>
|
||||
<img src="#" class="img-fluid rounded-circle" alt="avatar"
|
||||
style="height: 128px;width: 128px;display: none"
|
||||
id="custom_avatar"/>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<label class="form-label" for="customFile">请选择要上传的图片</label>
|
||||
<input type="file" class="form-control" id="customFile" name="avatar"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center mt-lg-5">
|
||||
<%-- <button type="submit" class="btn btn-secondary btn-lg" onclick="save()">--%>
|
||||
<%-- SAVE--%>
|
||||
<%-- </button>--%>
|
||||
<%-- Todo: 换成消息框--%>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">
|
||||
<i class="fas fa-circle-info me-2"></i>提示
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-mdb-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<c:if test="${not empty message}">
|
||||
${message}
|
||||
</c:if>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" data-mdb-dismiss="modal">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!--Main layout-->
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-link text-center text-lg-start ">
|
||||
</footer>
|
||||
<!-- Footer -->
|
||||
|
||||
|
||||
<script type="text/javascript" src="${pageContext.request.contextPath}/resources/js/mdb.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
<c:if test="${not empty message && message ne 'null'}">
|
||||
$('#exampleModal').modal('show');
|
||||
</c:if>
|
||||
|
||||
$('#customFile').on('change', function() {
|
||||
var file = this.files[0]; // 获取选择的文件
|
||||
|
||||
// 检查是否选择了文件
|
||||
if (!file) {
|
||||
// 如果没有选择文件,执行相应的操作
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建FormData对象,将文件数据附加到其中
|
||||
var formData = new FormData();
|
||||
formData.append('avatar', file);
|
||||
|
||||
// 发送AJAX请求到后端的uploadAvatar方法
|
||||
$.ajax({
|
||||
url: 'uploadAvatar',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false, // 告诉jQuery不要处理FormData对象
|
||||
contentType: false, // 告诉jQuery不要设置Content-Type请求头
|
||||
success: function(response) {
|
||||
// 成功上传后的操作
|
||||
$('#default_avatar').hide(); // 隐藏默认头像
|
||||
$('#custom_avatar').attr('src', response.avatarUrl).show(); // 更新自定义头像的图像源
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.log('上传失败:', error);
|
||||
alert('上传失败,请重试');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user