avatar upload and fetch function√

Signed-off-by: Chenx221 <chenx221@yandex.com>
This commit is contained in:
Chenx221 2023-06-19 16:23:27 +08:00
parent 0181f98b45
commit fe8003faf5
23 changed files with 752 additions and 7 deletions

View File

@ -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>

View File

@ -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"/>

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -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>-->

View File

@ -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();
}
}
}

View File

@ -25,4 +25,8 @@ public interface UserMapper {
int enabledUser(int id);
int getDetailByUsername(String username);
void setAvatar(User user);
String getAvatar(String username);
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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"/>

View File

@ -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>

View File

@ -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"

View File

@ -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>

View 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>