refine project & add most new further

1. add account page.
2. support auto redirect for error page.
3. test and fix bug for login and register.
4. drop old api and jsp pages for project.

Signed-off-by: Puqns67 <me@puqns67.icu>
This commit is contained in:
Puqns67 2023-09-15 22:54:40 +08:00
parent 2ddb2d2602
commit a541931772
Signed by: Puqns67
GPG Key ID: 9669DF042554F536
23 changed files with 207 additions and 799 deletions

18
pom.xml
View File

@ -61,30 +61,20 @@
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-kotlin</artifactId>
<version>2.0.40</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
</dependency>
<!-- Other -->
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.40</version>
</dependency>
</dependencies>
<build>

View File

@ -1,7 +0,0 @@
package team8.fruitable.constant
enum class UserType {
Admin,
User,
Guest
}

View File

@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.servlet.mvc.support.RedirectAttributes
import team8.fruitable.controller.util.Util.Companion.error
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.AccountRepository
@ -18,10 +19,6 @@ class Account(private val repository: AccountRepository) {
return token?.let(repository::findByToken)
}
private fun hasAdminPermissions(token: String?): Boolean {
return this.getCurrentUser(token)?.isAdmin ?: false
}
private fun updateToken(response: HttpServletResponse, token: String, path: String = "/", age: Int = 2678400) {
val cookie = Cookie("TOKEN", token)
cookie.path = path
@ -29,53 +26,66 @@ class Account(private val repository: AccountRepository) {
response.addCookie(cookie)
}
fun error(
redirectAttributes: RedirectAttributes,
title: String,
message: String,
redirect: String = "/"
): String {
redirectAttributes.addFlashAttribute("title", title)
redirectAttributes.addFlashAttribute("message", message)
redirectAttributes.addFlashAttribute("redirect", redirect)
return "redirect:/error"
}
@PostMapping("/login")
fun login(
response: HttpServletResponse,
attributes: RedirectAttributes,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String
@CookieValue("TOKEN", required = false) token: String?,
@RequestParam("name") name: String,
@RequestParam("password") password: String
): String {
if (this.getCurrentUser(token) != null) return error(attributes, "登录", "当前已登录账户")
val user = repository.findByName(name) ?: return error(attributes, "登录", "账户不存在")
if (!user.testPassword(password)) return error(attributes, "登录", "密码错误")
val user = repository.findByName(name) ?: return error(attributes, "登录", "账户不存在", "/login")
if (!user.testPassword(password)) return error(attributes, "登录", "密码错误", "/login")
user.updateToken()
user.updateLoginTime()
repository.save(user)
updateToken(response, user.token)
return "redirect:/";
return "redirect:/"
}
@PostMapping("/register")
fun register(
response: HttpServletResponse,
attributes: RedirectAttributes,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?
@CookieValue("TOKEN", required = false) token: String?,
@RequestParam("name") name: String,
@RequestParam("password") password: String,
@RequestParam("age", required = false) age: Int?,
@RequestParam("gender", required = false) gender: String?,
@RequestParam("phone", required = false) phone: String?,
@RequestParam("email", required = false) email: String?,
@RequestParam("address", required = false) address: String?
): String {
if (this.getCurrentUser(token) != null) return error(attributes, "登录", "当前已登录账户")
if (this.getCurrentUser(token) != null) return error(attributes, "注册", "当前已登录账户")
val user = repository.save(User(name, password, age, gender, phone, email, address))
updateToken(response, user.token)
return "redirect:/";
return "redirect:/"
}
@PostMapping("/update")
fun update(
response: HttpServletResponse,
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?,
@RequestParam("password_old") passwordOld: String,
@RequestParam("name") name: String,
@RequestParam("password", required = false) password: String?,
@RequestParam("password_confirm", required = false) passwordConfirm: String?,
@RequestParam("age", required = false) age: Int?,
@RequestParam("gender", required = false) gender: String?,
@RequestParam("phone", required = false) phone: String?,
@RequestParam("email", required = false) email: String?,
@RequestParam("address", required = false) address: String?,
@RequestParam("redirect", required = false) redirect: String?
): String {
val user = this.getCurrentUser(token) ?: return error(attributes, "更新", "账户未登录")
if (!user.testPassword(passwordOld)) return error(attributes, "更新", "正在使用的密码不正确", "/account")
if (password != passwordConfirm) return error(attributes, "更新", "密码与确认密码不相同", "/account")
user.update(name, password, age, gender, phone, email, address)
repository.save(user)
updateToken(response, user.token)
return "redirect:/account"
}
@RequestMapping("/logout")

View File

@ -1,144 +0,0 @@
package team8.fruitable.controller.api
import jakarta.servlet.http.Cookie
import jakarta.servlet.http.HttpServletResponse
import org.springframework.web.bind.annotation.*
import team8.fruitable.constant.UserType
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.AccountRepository
import team8.fruitable.util.ResultBuilderJson
@RestController
@RequestMapping("/api/v1/account")
class AccountApi(private val repository: AccountRepository) {
private fun getCurrentUser(token: String?): User? {
return token?.let(repository::findByToken)
}
private fun hasAdminPermissions(token: String?): Boolean {
return this.getCurrentUser(token)?.isAdmin ?: false
}
private fun updateToken(response: HttpServletResponse, token: String, path: String = "/", age: Int = 2678400) {
val cookie = Cookie("TOKEN", token)
cookie.path = path
cookie.maxAge = age
response.addCookie(cookie)
}
@GetMapping("/info", produces = ["application/json"])
fun infoMe(
@CookieValue(value = "TOKEN", required = false) token: String?
): String {
val user = this.getCurrentUser(token) ?: return ResultBuilderJson<Any>("账户未登录").toJson()
return ResultBuilderJson(user.asMap(UserType.User)).toJson()
}
@GetMapping("/info/{id}", produces = ["application/json"])
fun info(
@CookieValue(value = "TOKEN", required = false) token: String?, @PathVariable id: Long
): String {
val queryUser = repository.findById(id).orElse(null) ?: return ResultBuilderJson<Any>("账户不存在").toJson()
val currentUser = this.getCurrentUser(token)
return ResultBuilderJson(
queryUser.asMap(if (currentUser != null && (currentUser.id == id || currentUser.isAdmin)) UserType.User else UserType.Guest)
).toJson()
}
//@PostMapping
@RequestMapping("/login", produces = ["application/json"])
fun login(
response: HttpServletResponse,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String
): String {
if (this.getCurrentUser(token) != null) return ResultBuilderJson<Any>("当前已登录账户").toJson()
val user = repository.findByName(name) ?: return ResultBuilderJson<Any>("账户不存在").toJson()
if (!user.testPassword(password)) return ResultBuilderJson<Any>("密码错误").toJson()
user.updateToken()
user.updateLoginTime()
repository.save(user)
updateToken(response, user.token)
return ResultBuilderJson<Any>("success", "登录成功").toJson()
}
@RequestMapping("/logout", produces = ["application/json"])
fun logout(response: HttpServletResponse): String {
updateToken(response, "", age = 0)
return ResultBuilderJson<Any>("success", "注销成功").toJson()
}
@RequestMapping("/register", produces = ["application/json"])
fun register(
response: HttpServletResponse,
@CookieValue(value = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?
): String {
if (this.getCurrentUser(token) != null) return ResultBuilderJson<Any>("当前已登录账户").toJson()
val user = repository.save(User(name, password, age, gender, phone, email, address))
updateToken(response, user.token)
return ResultBuilderJson<Any>("success", "注册成功").toJson()
}
@RequestMapping("/update", produces = ["application/json"])
fun update(
response: HttpServletResponse,
@CookieValue(name = "TOKEN", required = false) token: String?,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?
): String {
val user = this.getCurrentUser(token) ?: return ResultBuilderJson<Any>("账户未登录").toJson()
user.update(name, password, age, gender, phone, email, address)
repository.save(user)
updateToken(response, user.token)
return ResultBuilderJson<Any>("success", "更新账户信息成功").toJson()
}
@GetMapping("/admin/info/{id}", produces = ["application/json"])
fun infoAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long,
): String {
if (this.hasAdminPermissions(token)) return ResultBuilderJson<Any>("无管理员权限").toJson()
return ResultBuilderJson(repository.findById(id)).toJson()
}
@DeleteMapping("/admin/remove/{id}", produces = ["application/json"])
fun removeAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long,
): String {
if (this.hasAdminPermissions(token)) return ResultBuilderJson<Any>("无管理员权限").toJson()
// TODO: 完成管理员删除方法
return ResultBuilderJson(repository.findById(id)).toJson()
}
@PostMapping("/admin/update/{id}", produces = ["application/json"])
fun updateAdmin(
@CookieValue(value = "TOKEN", required = false) token: String?,
@PathVariable id: Long,
@RequestParam(name = "name") name: String,
@RequestParam(name = "password") password: String,
@RequestParam(name = "age", required = false) age: Int?,
@RequestParam(name = "gender", required = false) gender: String?,
@RequestParam(name = "phone", required = false) phone: String?,
@RequestParam(name = "email", required = false) email: String?,
@RequestParam(name = "address", required = false) address: String?
): String {
if (this.hasAdminPermissions(token)) return ResultBuilderJson<Any>("无管理员权限").toJson()
// TODO: 完成管理员更新账户数据方法
return ResultBuilderJson(repository.findById(id)).toJson()
}
}

View File

@ -1,4 +0,0 @@
package team8.fruitable.controller.api
class Cart {
}

View File

@ -1,25 +0,0 @@
package team8.fruitable.controller.api
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.AccountRepository
import team8.fruitable.datebase.repository.ItemRepository
import team8.fruitable.util.ResultBuilderJson
@RestController
class Item(private val itemRepository: ItemRepository, private val userRepository: AccountRepository) {
private fun getCurrentUser(token: String?): User? {
return token?.let(userRepository::findByToken)
}
private fun hasAdminPermissions(token: String?): Boolean {
return this.getCurrentUser(token)?.isAdmin ?: false
}
@GetMapping("/api/v1/item/info/{id}", produces = ["application/json"])
fun info(@PathVariable id: Long): String {
return ResultBuilderJson(itemRepository.findById(id).orElse(null)).toJson()
}
}

View File

@ -1,4 +0,0 @@
package team8.fruitable.controller.api
class Order {
}

View File

@ -5,6 +5,8 @@ import org.springframework.ui.Model
import org.springframework.ui.set
import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.servlet.mvc.support.RedirectAttributes
import team8.fruitable.controller.util.Util.Companion.error
import team8.fruitable.datebase.entity.User
import team8.fruitable.datebase.repository.AccountRepository
@ -47,4 +49,21 @@ class Pages(private val repository: AccountRepository) {
this.getCurrentUser(token)?.let { model["user"] = it }
return "register"
}
@RequestMapping("/account")
fun account(
model: Model,
attributes: RedirectAttributes,
@CookieValue("TOKEN", required = false) token: String?
): String {
model["isAccount"] = true
val user = this.getCurrentUser(token) ?: return error(attributes, "更新", "账户未登录", "/login")
when (user.gender) {
"M"-> model["isGenderAsMale"] = true
"F" -> model["isGenderAsFemale"] = true
else -> model["isGenderAsUnknown"] = true
}
model["user"] = user
return "account"
}
}

View File

@ -0,0 +1,19 @@
package team8.fruitable.controller.util
import org.springframework.web.servlet.mvc.support.RedirectAttributes
class Util {
companion object {
fun error(
redirectAttributes: RedirectAttributes,
title: String,
message: String,
redirect: String = "/"
): String {
redirectAttributes.addFlashAttribute("title", title)
redirectAttributes.addFlashAttribute("message", message)
redirectAttributes.addFlashAttribute("redirect", redirect)
return "redirect:/error"
}
}
}

View File

@ -2,12 +2,10 @@ package team8.fruitable.datebase.entity
import com.fasterxml.jackson.annotation.JsonView
import jakarta.persistence.*
import team8.fruitable.constant.UserType
import team8.fruitable.util.Util
import java.time.LocalDateTime
import java.util.*
@Entity
@Table(name = "users")
class User(
@ -94,28 +92,28 @@ class User(
this.address = address
}
final fun genPassword(password: String): String {
private final fun genPassword(password: String): String {
return Util.hash(password)
}
fun update(
name: String,
password: String,
age: Int?,
gender: String?,
phone: String?,
email: String?,
address: String?,
isAdmin: Boolean = false
name: String? = null,
password: String? = null,
age: Int? = null,
gender: String? = null,
phone: String? = null,
email: String? = null,
address: String? = null,
isAdmin: Boolean? = null
) {
this.name = name
this.updatePassword(password)
if (!name.isNullOrBlank()) this.name = name
if (!password.isNullOrBlank()) this.updatePassword(password)
this.age = age
this.gender = gender
if (!gender.isNullOrBlank()) this.gender = gender
this.phone = phone
this.email = email
this.address = address
this.isAdmin = isAdmin
isAdmin?.let { this.isAdmin = it }
this.updateToken()
}
@ -134,28 +132,4 @@ class User(
fun updateToken() {
this.token = UUID.randomUUID().toString()
}
fun asMap(userType: UserType): Map<String, Any?> {
val result: MutableMap<String, Any?> = mutableMapOf(
"id" to this.id,
"name" to this.name,
"createTime" to this.createTime,
"loginTime" to this.loginTime,
"age" to this.age,
"gender" to this.gender,
"email" to this.email,
)
if (userType == UserType.User || userType == UserType.Admin) result += mapOf(
"phone" to this.phone,
"address" to this.address,
"isAdmin" to this.isAdmin,
"carts" to this.carts,
"orders" to this.orders
)
if (userType == UserType.Admin) result += mapOf(
"password" to this.password,
"token" to this.token,
)
return result
}
}

View File

@ -1,54 +0,0 @@
package team8.fruitable.util
import com.alibaba.fastjson2.toJSONString
import java.time.LocalDateTime
import java.util.*
class ResultBuilderJson<T> {
var status: String = "auto"
var message: String = ""
val timestamp: LocalDateTime = LocalDateTime.now()
var content: T? = null
constructor(content: T?) {
this.content = content
}
constructor(message: String) {
this.message = message
}
constructor(status: String, message: String) : this(message) {
this.status = status
}
constructor(message: String, content: T?) : this(content) {
this.message = message
}
constructor(status: String, message: String, content: T?) : this(message, content) {
this.status = status
}
constructor(content: Optional<T>) {
this.content = content.orElse(null)
}
constructor(message: String, content: Optional<T>) : this(content) {
this.message = message
}
constructor(status: String, message: String, content: Optional<T>) : this(message, content) {
this.status = status
}
fun toJson(): String {
if (status == "auto") status = if (content == null) "error"
else "success"
return this.toJSONString()
}
override fun toString(): String {
return this.toJson()
}
}

View File

@ -6,7 +6,7 @@ class Util {
companion object {
fun hash(input: String, algorithm: String = "SHA-256"): String {
return MessageDigest.getInstance(algorithm).digest(input.toByteArray())
.fold("") { str, it -> str + "%02x".format(it) }
.joinToString("") { "%02x".format(it) }
}
}
}

View File

@ -4,7 +4,7 @@ spring:
username: root
password: password
jpa:
show-sql: true
open-in-view: true
hibernate:
ddl-auto: update
server:

View File

@ -1,147 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:action name="auth" var="AuthInfo" />
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<title>账户 - 67购物网站</title>
<script type="text/javascript" src="../static/scripts/header.js"></script>
<script type="text/javascript" src="../static/scripts/clock.js"></script>
<script type="text/javascript" src="../static/scripts/top.js"></script>
<script type="text/javascript" src="../static/scripts/footer.js"></script>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/header.css">
<link type="text/css" rel="stylesheet" href="../static/styles/clock.css">
<link type="text/css" rel="stylesheet" href="../static/styles/top.css">
<link type="text/css" rel="stylesheet" href="../static/styles/footer.css">
<link type="text/css" rel="stylesheet" href="../static/styles/form.css">
<link type="text/css" rel="stylesheet" href="../static/styles/user.css">
<!-- 外部小组件 -->
<script src="../static/scripts/lib/anime.min.js"></script>
<script async src="../static/scripts/lib/explosion.min.js"></script>
</head>
<body>
<!-- 头部内容 -->
<div id="Header">
<div class="List Special Title">67购物网站</div>
<div class="List Link" href="index.jsp">
<span class="Text">首页</span>
</div>
<div class="List Link" href="activity.jsp">
<span class="Text">活动</span>
</div>
<div class="List Blank"></div>
<div class="List Special SearchBar">
<input class="InputBar" type="text" />
</div>
<div class="List Blank"></div>
<div class="List Button"><span class="Text">历史记录</span></div>
<div class="List Button"><span class="Text">购物车</span></div>
<s:if test="%{#AuthInfo.IsLogined}">
<div class="List Button Link" href="logout.action"><span class="Text">注销</span></div>
<s:if test="%{#AuthInfo.UserInfo.IsAdmin}">
<div class="List Button Link" href="edit.jsp"><span class="Text">编辑</span></div>
</s:if>
<div class="List Button Link" this><span class="Text">账户</span></div>
</s:if>
<s:else>
<div class="List Button Link" href="login.jsp"><span class="Text">登录</span></div>
<div class="List Button Link" href="register.jsp"><span class="Text">注册</span></div>
</s:else>
<div class="List Special Clock">
<span class="CLOCK"></span>
</div>
<div class="List Special PinHeader">
<img class="PIN" src="../static/images/pin.svg" checked />
</div>
</div>
<!-- 页面内容 -->
<div id="Contents">
<form class="TabForm" action="account.action" method="post">
<div class="TabTitle">账户</div>
<input type="hidden" name="id" value="<s:property value="%{#AuthInfo.UserInfo.Id}" />" />
<div class="TabFormItems">
<div class="TabFormItem">
<label class="ItemName" for="password_old">旧密码</label>
<input class="ItemInput" id="password_old" type="password" name="password_old" placeholder="请输入旧密码以更新下列数据" required />
</div>
<div class="TabFormItem">
<label class="ItemName" for="username">用户名</label>
<input class="ItemInput" id="username" type="text" name="username" placeholder="请输入新用户名" value="<s:property value="%{#AuthInfo.UserInfo.UserName}" />" />
</div>
<div class="TabFormItem">
<label class="ItemName" for="password">新密码</label>
<input class="ItemInput" id="password" type="password" name="password" placeholder="请输入新密码" />
</div>
<div class="TabFormItem">
<label class="ItemName" for="passwrod">确认新密码</label>
<input class="ItemInput" id="password_confirm" type="password" name="password_confirm" placeholder="请输入确认新密码" />
</div>
<div class="TabFormItem">
<label class="ItemName" for="age">年龄</label>
<input class="ItemInput" id="age" type="number" name="age" placeholder="请输入新年龄" value="<s:property value="%{#AuthInfo.UserInfo.Age}" />" />
</div>
<div class="TabFormItem">
<label class="ItemName" for="email">邮箱</label>
<input class="ItemInput" id="email" type="email" name="email" placeholder="请输入新邮箱" value="<s:property value="%{#AuthInfo.UserInfo.Email}" />" />
</div>
<div class="TabFormItem">
<input class="ItemInput" id="gender_null" type="radio" name="gender" value="N" <s:if test="%{#AuthInfo.UserInfo.Gender == \"N\"}">checked</s:if> />
<label class="ItemName" for="gender_null">未知</label>
<input class="ItemInput"id="gender_male" type="radio" name="gender" value="M" <s:if test="%{#AuthInfo.UserInfo.Gender == \"M\"}">checked</s:if> />
<label class="ItemName" for="gender_male">男性</label>
<input class="ItemInput"id="gender_female" type="radio" name="gender" value="F" <s:if test="%{#AuthInfo.UserInfo.Gender == \"F\"}">checked</s:if> />
<label class="ItemName" for="gender_female">女性</label>
</div>
</div>
<div class="TabButtons">
<button class="TabButton" type="submit">更新账户数据</button>
</div>
</form>
</div>
<!-- 页尾内容 -->
<div id="Footer">
<div class="Infos">
<div class="Icon"><img src="../static/images/icon.svg" /></div>
<div class="Title">67购物网站</div>
<div class="Contents">
<span>只做高质量商品销售~</span>
</div>
</div>
<div class="Links">
<div class="Title"></div>
<div class="Contents"></div>
</div>
</div>
<!-- 浮动内容 -->
<div id="Floater">
<!-- 回到顶层 -->
<div class="TOP"></div>
<canvas
class="fireworks"
style="
position: fixed;
left: 0;
top: 0;
z-index: 1;
pointer-events: none;
"
></canvas>
</div>
</body>
</html>

View File

@ -0,0 +1,101 @@
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<title>账户 - 67购物网站</title>
<script type="text/javascript" src="scripts/header.js"></script>
<script type="text/javascript" src="scripts/clock.js"></script>
<script type="text/javascript" src="scripts/top.js"></script>
<script type="text/javascript" src="scripts/footer.js"></script>
<link type="image/x-icon" rel="icon" href="images/favicon.ico">
<link type="text/css" rel="stylesheet" href="styles/header.css">
<link type="text/css" rel="stylesheet" href="styles/clock.css">
<link type="text/css" rel="stylesheet" href="styles/top.css">
<link type="text/css" rel="stylesheet" href="styles/footer.css">
<link type="text/css" rel="stylesheet" href="styles/form.css">
<link type="text/css" rel="stylesheet" href="styles/user.css">
<!-- 外部小组件 -->
<script src="scripts/lib/anime.min.js"></script>
<script async src="scripts/lib/explosion.min.js"></script>
</head>
<body>
{{> header }}
<!-- 页面内容 -->
<div id="Contents">
<form class="TabForm" action="/action/account/update" method="post">
<div class="TabTitle">账户</div>
<div class="TabFormItems">
<div class="TabFormItem">
<label class="ItemName" for="password_old">正在使用的密码</label>
<input class="ItemInput" id="password_old" type="password" name="password_old"
placeholder="请输入您正在使用的密码以更新下列数据" required/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="name">用户名</label>
<input class="ItemInput" id="name" type="text" name="name" placeholder="请输入新用户名"
value="{{ user.name }}"/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="password">新密码</label>
<input class="ItemInput" id="password" type="password" name="password" placeholder="请输入新密码"/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="password_confirm">确认新密码</label>
<input class="ItemInput" id="password_confirm" type="password" name="password_confirm"
placeholder="请输入确认新密码"/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="age">年龄</label>
<input class="ItemInput" id="age" type="number" name="age" placeholder="请输入新年龄"
{{# user.age }}value="{{ user.age }}"{{/user.age}}/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="phone">手机号码</label>
<input class="ItemInput" id="phone" type="tel" name="phone" placeholder="请输入新手机号"
{{# user.phone }}value="{{ user.phone }}{{/ user.phone }}"/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="email">邮箱</label>
<input class="ItemInput" id="email" type="email" name="email" placeholder="请输入新邮箱"
{{# user.email }}value="{{ user.email }}"{{/ user.email }}/>
</div>
<div class="TabFormItem">
<label class="ItemName" for="address">地址</label>
<input class="ItemInput" id="address" type="text" name="address" placeholder="请输入新地址"
{{# user.address }}value="{{ user.address }}"{{/ user.address }}/>
</div>
<div class="TabFormItem">
<input class="ItemInput" id="gender_null" type="radio" name="gender" value="N"
{{# isGenderAsUnknown }}checked{{/ isGenderAsUnknown }} />
<label class="ItemName" for="gender_null">未知</label>
<input class="ItemInput" id="gender_male" type="radio" name="gender" value="M"
{{# isGenderAsMale }}checked{{/ isGenderAsMale }} />
<label class="ItemName" for="gender_male">男性</label>
<input class="ItemInput" id="gender_female" type="radio" name="gender" value="F"
{{# isGenderAsFemale }}checked{{/ isGenderAsFemale }} />
<label class="ItemName" for="gender_female">女性</label>
</div>
</div>
<div class="TabButtons">
<button class="TabButton" type="submit">更新账户数据</button>
</div>
</form>
</div>
{{> footer }}
</body>
</html>

View File

@ -1,96 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:action name="auth" var="AuthInfo" />
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<title>活动 - 67购物网站</title>
<script type="text/javascript" src="../static/scripts/header.js"></script>
<script type="text/javascript" src="../static/scripts/clock.js"></script>
<script type="text/javascript" src="../static/scripts/top.js"></script>
<script type="text/javascript" src="../static/scripts/footer.js"></script>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/header.css">
<link type="text/css" rel="stylesheet" href="../static/styles/clock.css">
<link type="text/css" rel="stylesheet" href="../static/styles/top.css">
<link type="text/css" rel="stylesheet" href="../static/styles/footer.css">
<!-- 此处借用 item 页面的部分属性 -->
<link type="text/css" rel="stylesheet" href="../static/styles/item.css">
<!-- 外部小组件 -->
<script src="../static/scripts/lib/anime.min.js"></script>
<script async src="../static/scripts/lib/explosion.min.js"></script>
</head>
<body>
<!-- 头部内容 -->
<div id="Header">
<div class="List Special Title">67购物网站</div>
<div class="List Link" href="index.jsp">
<span class="Text">首页</span>
</div>
<div class="List Link" this>
<span class="Text">活动</span>
</div>
<div class="List Blank"></div>
<div class="List Special SearchBar">
<input class="InputBar" type="text" />
</div>
<div class="List Blank"></div>
<div class="List Button"><span class="Text">历史记录</span></div>
<div class="List Button"><span class="Text">购物车</span></div>
<s:if test="%{#AuthInfo.IsLogined}">
<div class="List Button Link" href="logout.action"><span class="Text">注销</span></div>
<s:if test="%{#AuthInfo.UserInfo.IsAdmin}">
<div class="List Button Link" href="edit.jsp"><span class="Text">编辑</span></div>
</s:if>
<div class="List Button Link" href="account.jsp"><span class="Text">账户</span></div>
</s:if>
<s:else>
<div class="List Button Link" href="login.jsp"><span class="Text">登录</span></div>
<div class="List Button Link" href="register.jsp"><span class="Text">注册</span></div>
</s:else>
<div class="List Special Clock">
<span class="CLOCK"></span>
</div>
<div class="List Special PinHeader">
<img class="PIN" src="../static/images/pin.svg" checked />
</div>
</div>
<!-- 页面内容 -->
<div id="Contents">此处由于时间不足,不完善,请见谅</div>
<!-- 页尾内容 -->
<div id="Footer">
<div class="Infos">
<div class="Icon"><img src="../static/images/icon.svg" /></div>
<div class="Title">67购物网站</div>
<div class="Contents">
<span>只做高质量商品销售~</span>
</div>
</div>
<div class="Links">
<div class="Title"></div>
<div class="Contents"></div>
</div>
</div>
<!-- 浮动内容 -->
<div id="Floater">
<!-- 回到顶层 -->
<div class="TOP"></div>
<canvas
class="fireworks"
style="
position: fixed;
left: 0;
top: 0;
z-index: 1;
pointer-events: none;
"
></canvas>
</div>
</body>
</html>

View File

@ -1,163 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:action name="auth" var="AuthInfo" />
<s:action name="edit" var="EditInfo" />
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<s:if test="%{!#AuthInfo.UserInfo.IsAdmin}">
<meta http-equiv="refresh" content="0;url=index.jsp">
</s:if>
<title>编辑 - 67购物网站</title>
<script type="text/javascript" src="../static/scripts/header.js"></script>
<script type="text/javascript" src="../static/scripts/clock.js"></script>
<script type="text/javascript" src="../static/scripts/top.js"></script>
<script type="text/javascript" src="../static/scripts/footer.js"></script>
<script type="text/javascript" src="../static/scripts/edit.js"></script>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/header.css">
<link type="text/css" rel="stylesheet" href="../static/styles/clock.css">
<link type="text/css" rel="stylesheet" href="../static/styles/top.css">
<link type="text/css" rel="stylesheet" href="../static/styles/footer.css">
<link type="text/css" rel="stylesheet" href="../static/styles/edit.css">
<!-- 外部小组件 -->
<script src="../static/scripts/lib/anime.min.js"></script>
<script async src="../static/scripts/lib/explosion.min.js"></script>
</head>
<body>
<!-- 头部内容 -->
<div id="Header">
<div class="List Special Title">67购物网站</div>
<div class="List Link" href="index.jsp">
<span class="Text">首页</span>
</div>
<div class="List Link" href="activity.jsp">
<span class="Text">活动</span>
</div>
<div class="List Blank"></div>
<div class="List Special SearchBar">
<input class="InputBar" type="text" />
</div>
<div class="List Blank"></div>
<div class="List Button"><span class="Text">历史记录</span></div>
<div class="List Button"><span class="Text">购物车</span></div>
<s:if test="%{#AuthInfo.IsLogined}">
<div class="List Button Link" href="logout.action"><span class="Text">注销</span></div>
<s:if test="%{#AuthInfo.UserInfo.IsAdmin}">
<div class="List Button Link" this><span class="Text">编辑</span></div>
</s:if>
<div class="List Button Link" href="account.jsp"><span class="Text">账户</span></div>
</s:if>
<s:else>
<div class="List Button Link" href="login.jsp"><span class="Text">登录</span></div>
<div class="List Button Link" href="register.jsp"><span class="Text">注册</span></div>
</s:else>
<div class="List Special Clock">
<span class="CLOCK"></span>
</div>
<div class="List Special PinHeader">
<img class="PIN" src="../static/images/pin.svg" checked />
</div>
</div>
<!-- 页面内容 -->
<div id="Contents">
<div class="Editors">
<div class="Title">
<form class="Search" action="edit.jsp" method="post">
<s:select name="type" list="#{'ALL': '搜索全部', 'ID': '以ID搜索', 'USERNAME': '以用户名搜索', 'CREATE_DATE': '以帐户注册时间搜索', 'LAST_LOGIN_DATE': '以最后登录时间搜索', 'AGE': '以年龄搜索', 'GENDER': '以性别搜索', 'EMAIL': '以邮箱搜索', 'IS_ADMIN': '以管理员状态搜索'}" value="%{#EditInfo.SearchType}" />
<s:textfield name="search" placeholder="请在此处输入你想要搜索的内容..." value="%{#EditInfo.Search}" />
<button type="submit">搜索</button>
</form>
<button onclick="javascript:location.reload();">刷新</button>
</div>
<table class="Result">
<thead>
<tr>
<td>ID</td>
<td>用户名</td>
<td>帐户创建时间</td>
<td>最后登录时间</td>
<td>年龄</td>
<td>性别</td>
<td>邮箱</td>
<td>管理员</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<s:iterator value="%{#EditInfo.Users}" var="UserInfo">
<tr id="<s:property value='#UserInfo.Id' />">
<td><s:property value="#UserInfo.Id" /></td>
<td><s:property value="#UserInfo.UserName" /></td>
<td><s:property value="#UserInfo.CreateDate" /></td>
<td><s:property value="#UserInfo.LastLoginDate" /></td>
<td><s:property value="#UserInfo.AgePretty" /></td>
<td><s:property value="#UserInfo.GenderPretty" /></td>
<td><s:property value="#UserInfo.EmailPretty" /></td>
<td><s:property value="#UserInfo.IsAdminPretty" /></td>
<td>
<button class="update">编辑</button>
<button class="remove">删除</button>
</td>
</tr>
</s:iterator>
</tbody>
</table>
<div class="Pages">
<a href="edit.jsp?page=0">首页</a>
<s:iterator begin="%{#EditInfo.StartPage}" end="%{#EditInfo.StopPage}" var="PageNumber">
<s:if test="%{#PageNumber == #EditInfo.NowPageStr}">
<span>第 <s:property value="%{#PageNumber + 1}" /> 页</span>
</s:if>
<s:else>
<a href="edit.jsp?page=<s:property value="%{#PageNumber}" />">第 <s:property value="%{#PageNumber + 1}"/> 页</a>
</s:else>
</s:iterator>
<a href="edit.jsp?page=<s:property value="%{#EditInfo.EndPage}" />">尾页</a>
</div>
</div>
<div class="EditPanel">
<iframe id="Displayer" class="Panel" name="displayer"></iframe>
</div>
</div>
<!-- 页尾内容 -->
<div id="Footer">
<div class="Infos">
<div class="Icon"><img src="../static/images/icon.svg" /></div>
<div class="Title">67购物网站</div>
<div class="Contents">
<span>只做高质量商品销售~</span>
</div>
</div>
<div class="Links">
<div class="Title"></div>
<div class="Contents"></div>
</div>
</div>
<!-- 浮动内容 -->
<div id="Floater">
<!-- 回到顶层 -->
<div class="TOP"></div>
<canvas
class="fireworks"
style="
position: fixed;
left: 0;
top: 0;
z-index: 1;
pointer-events: none;
"
></canvas>
</div>
</body>
</html>

View File

@ -21,6 +21,10 @@
<!-- 外部小组件 -->
<script src="scripts/lib/anime.min.js"></script>
<script async src="scripts/lib/explosion.min.js"></script>
<!-- 自动跳转 -->
{{# redirect }}
<meta http-equiv="refresh" content="3;url={{ redirect }}">
{{/ redirect }}
</head>
<body>

View File

@ -30,7 +30,7 @@
<!-- 页面内容 -->
<div id="Contents">
<form class="TabForm" action="action/account/login" method="post">
<form class="TabForm" action="/action/account/login" method="post">
<div class="TabTitle">登录</div>
<div class="TabFormItems">

View File

@ -30,13 +30,13 @@
<!-- 页面内容 -->
<div id="Contents">
<form class="TabForm" action="action/account/register" method="post">
<form class="TabForm" action="/action/account/register" method="post">
<div class="TabTitle">注册</div>
<div class="TabFormItems">
<div class="TabFormItem">
<label class="ItemName" for="name">用户名</label>
<input class="ItemInput" id="name" type="text" name="username" placeholder="请输入用户名" required/>
<input class="ItemInput" id="name" type="text" name="name" placeholder="请输入用户名" required/>
</div>
<div class="TabFormItem">

View File

@ -1,23 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>移除用户 - 67购物网站</title>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/remove.css">
</head>
<body>
<form action="remove.action" method="post">
<input type="hidden" name="id" value="<s:property value="UserInfo.Id" />" />
<h3>确定移除此用户?</h3>
<p>用户名: <s:property value="UserInfo.UserName" /></p>
<button type="submit">确定</button>
</form>
</body>
</html>

View File

@ -1,15 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>成功 - 67购物网站</title>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/success.css">
</head>
<body>
<h2>操作已完成!</h2>
</body>
</html>

View File

@ -1,27 +0,0 @@
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更新用户 - 67购物网站</title>
<link type="image/x-icon" rel="icon" href="../static/images/favicon.ico">
<link type="text/css" rel="stylesheet" href="../static/styles/update.css">
</head>
<body>
<h3>更新此用户的信息</h3>
<form action="update.action" method="post">
<div class="i"><s:hidden name="id" value="%{UserInfo.Id}" /></div>
<div class="i"><s:textfield name="username" label="用户名" value="%{UserInfo.UserName}" /></div>
<div class="i"><s:password name="password" label="密码" /></div>
<div class="i"><s:password name="password_confirm" label="确认密码" /></div>
<div class="i"><s:textfield name="age" type="number" label="年龄" value="%{UserInfo.Age}" /></div>
<div class="i"><s:textfield name="email" type="email" label="邮箱" value="%{UserInfo.Email}" /></div>
<div class="i"><s:select name="gender" label="性别" list="#{'N': '未知', 'M':'男性', 'F': '女性'}" value="%{UserInfo.Gender}" /></div>
<div><s:checkbox name="admin" label="管理员" value="%{UserInfo.IsAdmin}"/></div>
<s:submit value="确定" />
</form>
</body>
</html>