01基于 Jakarta EE开发 : Servlet + Thymeleaf图书管理系统
一、前提准备 创建工程 JDK 25、IDEA2025 、tomcat-11.0.20 项目依赖已正确引入Thymeleaf 3.1.2 Jakarta EE11 Servlet 6.0lombok1.18.42druid1.2.16mysql-connector-java8.0.33。!-- Thymeleaf依赖 -- dependency groupIdorg.thymeleaf/groupId artifactIdthymeleaf/artifactId version3.1.2.RELEASE/version /dependency !-- lombok依赖 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.42/version /dependency !-- druid -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.16/version /dependency !-- mysql驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency二、核心配置步骤1.配置 Thymeleaf 模板路径Thymeleaf 的模板文件默认放在src/main/webapp/WEB-INF/templates/下需手动创建目录。2.CustomTemplateEngine模板引擎类package com.hnjt.thymeleaf; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.WebContext; import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.templateresolver.WebApplicationTemplateResolver; import org.thymeleaf.web.servlet.IServletWebExchange; import org.thymeleaf.web.servlet.JakartaServletWebApplication; import java.io.IOException; /** * 对于一个JavaWeb应用而言我们只需要配置一套模板引擎即可所有的请求都通过该模板引擎来解析网页。 * 单例模式。本类中还提供了一个对请求进行解析的方法方便我们使用。 */ public class CustomTemplateEngine { // 定义一个静态变量用于保存模板引擎对象 private static CustomTemplateEngine webApplication; // 模板引擎对象 private TemplateEngine templateEngine; // 创建JakartaServletWebApplication对象 private JakartaServletWebApplication application; /** * 私有化构造方法防止外部直接创建对象 * param request */ private CustomTemplateEngine(HttpServletRequest request) { System.out.println(设置Thymeleaf模板引擎); // 创建Thymeleaf的JakartaServletWebApplication对象 application JakartaServletWebApplication.buildApplication(request.getServletContext()); // 创建模板解析器对象 final WebApplicationTemplateResolver templateResolver new WebApplicationTemplateResolver(application); // 设置Thymeleaf的模板模式为HTML除此之外Thymeleaf还支持处理其他5种模板它们分别是XML、TEXT、JAVASCRIPT、CSS、RAW templateResolver.setTemplateMode(TemplateMode.HTML); // 设置模板文件的前缀即路径 templateResolver.setPrefix(/WEB-INF/templates/); // 设置模板文件的文件后缀 templateResolver.setSuffix(.html); // 设置缓存时间 templateResolver.setCacheTTLMs(Long.valueOf(3600000L)); // 设置缓存是否可用开发阶段我们需要将缓存关闭即设置为false templateResolver.setCacheable(false); // 创建模板引擎对象 templateEngine new TemplateEngine(); // 为模板引擎设置模板解析器 templateEngine.setTemplateResolver(templateResolver); } /** * 获取WebApplication对象 * param request 请求对象 * return 返回CustomTemplateEngine对象 */ public static CustomTemplateEngine getInstance(HttpServletRequest request) { if (webApplication null) { webApplication new CustomTemplateEngine(request); } return webApplication; } /** * 处理模板文件 * param templateName 模板文件的名称 * param request 请求对象 * param response 响应对象 * throws IOException IO异常 */ public void processTemplate(String templateName, HttpServletRequest request, HttpServletResponse response) throws IOException { // 创建IServletWebExchange对象 IServletWebExchange webExchange application.buildExchange(request, response); // 创建WebContext对象 WebContext context new WebContext(webExchange, webExchange.getLocale()); // 设置响应体内容类型和字符集 response.setContentType(text/html;charsetUTF-8); // 处理模板数据 templateEngine.process(templateName, context, response.getWriter()); } }3.LoginServlet类package com.hnjt.servlet; import com.hnjt.thymeleaf.CustomTemplateEngine; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; WebServlet(name login, value /login) public class LoginServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取模板引擎实例 CustomTemplateEngine engine CustomTemplateEngine.getInstance(req); //保存数据 req.setAttribute(username, zhangsan); req.setAttribute(password, 123456); // 处理模板文件将登录页面渲染到响应中 engine.processTemplate(login, req, resp); } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } } package com.hnjt.servlet; import com.hnjt.thymeleaf.CustomTemplateEngine; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; WebServlet(name login, value /login) public class LoginServlet extends HttpServlet { Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取模板引擎实例 CustomTemplateEngine engine CustomTemplateEngine.getInstance(req); //保存数据 req.setAttribute(username, zhangsan); req.setAttribute(password, 123456); // 处理模板文件将登录页面渲染到响应中 engine.processTemplate(login, req, resp); } Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }4.login.html页面!DOCTYPE html html langen xmlns:thhttp://www.thymeleaf/org head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用户登录/title link hrefhttps://cdn.jsdelivr.net/npm/tailwindcss2.2.19/dist/tailwind.min.css relstylesheet link hrefhttps://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css relstylesheet style .login-container { backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); } .input-field:focus { box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.3); } .btn-hover:hover { transform: translateY(-2px); box-shadow: 0 10px 25px -5px rgba(99, 102, 241, 0.4); } .form-animate { animation: fadeInUp 0.6s ease-out; } keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /style /head body classmin-h-screen bg-gradient-to-br from-indigo-500 via-purple-500 to-pink-500 flex items-center justify-center p-4 div classlogin-container bg-white/90 rounded-2xl p-8 w-full max-w-md form-animate div classtext-center mb-10 div classmx-auto bg-gray-200 border-2 border-dashed rounded-xl w-16 h-16 flex items-center justify-center mb-4 i classfas fa-user-circle text-3xl text-indigo-600/i /div h1 classtext-3xl font-bold text-gray-800欢迎回来/h1 p classtext-gray-600 mt-2请登录您的账户/p /div form idloginForm classspace-y-6 methodpost div label forusername classblock text-sm font-medium text-gray-700 mb-1用户名/label div classrelative div classabsolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none i classfas fa-user text-gray-400/i /div input typetext idusername th:value${username} classinput-field w-full pl-10 pr-3 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-200 placeholder请输入用户名 required /div /div div label forpassword classblock text-sm font-medium text-gray-700 mb-1密码/label div classrelative div classabsolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none i classfas fa-lock text-gray-400/i /div input typepassword idpassword th:value${password} classinput-field w-full pl-10 pr-3 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-200 placeholder请输入密码 required /div /div div classflex items-center justify-between div classflex items-center input idremember typecheckbox classh-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded label forremember classml-2 block text-sm text-gray-700记住我/label /div div classtext-sm a href# classfont-medium text-indigo-600 hover:text-indigo-500忘记密码/a /div /div div button typesubmit classbtn-hover w-full bg-indigo-600 text-white py-3 px-4 rounded-lg font-medium hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition duration-300 ease-in-out 登录 /button /div /form div classmt-8 text-center p classtext-gray-600 还没有账户 a href# classfont-medium text-indigo-600 hover:text-indigo-500立即注册/a /p /div div classmt-8 div classrelative div classabsolute inset-0 flex items-center div classw-full border-t border-gray-300/div /div div classrelative flex justify-center text-sm span classpx-2 bg-white text-gray-500其他登录方式/span /div /div div classmt-6 grid grid-cols-3 gap-3 button classw-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 i classfab fa-wechat text-green-500/i /button button classw-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 i classfab fa-qq text-blue-500/i /button button classw-full inline-flex justify-center py-2 px-4 border border-gray-300 rounded-md shadow-sm bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 i classfab fa-weibo text-red-500/i /button /div /div /div script document.getElementById(loginForm).addEventListener(submit, function(e) { e.preventDefault(); const username document.getElementById(username).value; const password document.getElementById(password).value; // 这里可以添加实际的登录逻辑 console.log(登录信息:, {username, password}); // 模拟登录成功效果 alert(欢迎回来, ${username}!); }); /script /body /html