Servlet配置实战:web.xml与@WebServlet注解全面解析
Servlet这个词放在今天动辄微服务、云原生的大环境下多少有点“老古董”的感觉。但你只要还在写Java后端不管用Spring Boot还是Spring MVC请求真正进来之后最终处理的还是Servlet容器那一层。很多新人会直接跳过Servlet觉得Spring Boot里一个Controller就搞定了结果一遇到ServletRequest、Filter这些底层概念或者要在非Spring环境下写点接口时整个人就懵了。这篇内容来自我的入门实战笔记核心就两件事把Servlet这个规范真正讲透以及常见的两种配置方式——web.xml和WebServlet注解——分别怎么落地。适合刚学完Java语法和HTML基础、准备理解Java Web底层运行机制的读者也适合那些“用过但没细想过”的后端同学查漏补缺。1. Servlet到底解决了什么问题一个请求的完整旅程1.1 从地址栏到服务器函数中间隔了多少层你打开浏览器输入http://localhost:8080/hello按下回车这一瞬间发生了什么从计算机层面看浏览器向目标服务器的8080端口发起TCP连接然后按照HTTP协议送出一段纯文本请求报文。报文长这样GET /hello HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0服务器端某个进程一直在监听8080端口它拿到了这个字符串需要自己解析“哦这是一条GET请求路径是/hello”。然后再根据业务逻辑生成响应字符串通过同一个TCP连接返回给浏览器。这个过程本身不复杂但问题在于如果每个应用开发者都从解析TCP报文开始写那日子就没法过了。而且服务器里往往同时运行多个功能模块耗时的、高并发的、需要保存会话状态的如果全靠自己用ServerSocket手搓几乎等于回到原始社会。Servlet规范就是在这里被发明出来的。它把共性的东西——监听端口、解析HTTP报文、管理并发、处理会话——全部下沉到容器里完成Java程序员只需要遵循一套接口约定写自己的业务类容器会在合适的时机调用你写的方法。1.2 Servlet容器、HTTP协议与Servlet的分工我用一个饭馆类比来解释三者的关系。HTTP协议是点菜单的格式规范客人必须按照固定格式写清楚要什么菜、备注什么口味。Servlet容器是饭馆前台它负责接待客人、读取菜单、然后喊后厨做菜。而你写的Servlet就是后厨的厨师只管根据前台下单的内容把菜做出来。前台下单对应容器根据报文创建了两个对象HttpServletRequest封装了请求路径、参数、Header等信息和HttpServletResponse封装了响应的输出流、状态码等然后把这两个对象传给“厨师”——也就是你Servlet里的方法。至于怎么接收网络流、怎么解析报文、怎么处理并发连接这些都是容器的事你不用碰。这个分工决定了Servlet一个核心特性Servlet本身是平台无关的Java类它不直接接触Socket不直接解析HTTP文本一切都是面对对象操作。整个应用跑在ServletContext这个全局上下文里不同Servlet之间可以共享数据这又为后面聊到的Filter、Listener打下了基础。1.3 为什么不直接写ServerSocket加main方法确实有一批人用过纯ServerSocket写HTTP服务体验基本是解析请求头要自己写正则匹配路径要自己写状态行拼错一个空格浏览器就报错并发上来还得自己管理线程池Session管理基本靠一个ConcurrentHashMap硬扛。这些活不是不能干而是既容易出错又难维护。Servlet规范把“Web服务器中重复发生的事”抽象成接口和生命周期模型谁实现这个规范谁就是容器。Tomcat是其中最常用的一个实现。你只需要把写好的Servlet类打成War包扔进Tomcat的webapps目录容器负责实例化、初始化、调用、销毁共性问题全部由容器统一处理。这也是我反复跟初学者强调的学Servlet重心一半在Java代码另一半在理解容器的生命周期与映射机制。2. Servlet生命周期与核心API不只是背概念要理解容器为什么这样设计2.1 五步生命周期每一步容器都在把控Servlet从被容器识别到最终释放一共经历五个关键阶段加载与实例化、初始化init、处理请求service、进入可用状态、销毁destroy。加载与实例化发生在容器启动或第一次请求到达时。默认情况下Servlet不会在Tomcat启动时就实例化而是懒加载——只有第一次请求触达时才创建对象。你可以通过load-on-startup参数调整这个行为让某些重量级Servlet随容器启动就初始化。init()只执行一次是初始化资源的最佳位置例如读取配置参数、建立数据库连接池、加载缓存。这里千万注意不要把耗时操作写在构造函数里构造函数是Java对象层面的行为此时Servlet尚未获取ServletConfig拿不到web.xml里配置的初始化参数。所以init(ServletConfig)方法才是生命周期正式入口super.init(config)内部会保存config并把调用转发给无参init()这也是为什么覆写init时记得先调super。请求来了之后容器会调用service()方法默认实现根据请求的HTTP方法GET、POST、PUT、DELETE等分发给对应的doXxx()方法。整个服务期间同一个Servlet实例会服务多个线程这就是下一章要展开的线程安全问题的来源。容器关闭或应用卸载时destroy()会被调用用于释放资源。调用完成后Servlet对象成为垃圾等待GC回收。这套模型非常成熟理解它之后你在排查“为什么我的初始化日志没打”“为什么静态变量状态混乱”等问题时会清晰很多。2.2 HttpServlet的service、doGet、doPost到底怎么联动写Servlet时你继承的是HttpServlet它基于GenericServlet扩展出了HTTP能力。最核心的方法关系是这样的请求进来容器调用的是service(HttpServletRequest, HttpServletResponse)HttpServlet重写了这个方法它先判断请求方法然后分别调用doGet、doPost、doPut等。如果某个方法你没有覆写父类默认实现会向响应写入405错误提示Method Not Allowed。这里有个很常见的坑有些新手直接在Servlet里覆写了service()方法但忘了调用super.service()于是doGet和doPost整个就不会被触发。如果你确实需要在分发前做统一处理记住在service()里保留super.service()调用或者干脆用Filter做前置处理这样更符合分层规范。简单来说doGet适合无副作用或幂等的请求比如查询、跳转doPost适合有副作用的提交请求比如表单数据落库。虽然你强行在doGet里写业务也能跑但严格遵守语义能让你后续接触Spring MVC时理解更顺畅。2.3 request和response两个对象的边界感HttpServletRequest承载“浏览器发给服务器的一切”请求行、请求头、请求参数、表单体、Cookie、Session等。常用方法比如getParameter()、getParameterValues()、getHeader()、getSession()、getRequestDispatcher()前两个咱们的Demo里一会儿就会用到。HttpServletResponse则负责“服务器返回浏览器的一切”设定响应状态码、响应头、重定向路径以及通过getWriter()拿到PrintWriter写入响应体。值得留意的是在一次请求处理中一旦你调用了getWriter()并写入内容部分响应头可能就无法再修改了所以先设Header再写Body是稳妥习惯。3. 配置方式一web.xml声明式配置的完整细节3.1 web.xml文件位置与基本结构Servlet 2.5及更早版本所有Servlet配置都必须集中写在Web应用目录下的WEB-INF/web.xml里。这个文件既是部署描述符也是容器识别Web应用的重要标记虽然Servlet 3.0后非必须但传统项目里它依然常见。一个基本的web.xml长这样?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 servlet servlet-namehelloServlet/servlet-name servlet-classcom.demo.HelloServlet/servlet-class /servlet servlet-mapping servlet-namehelloServlet/servlet-name url-pattern/hello/url-pattern /servlet-mapping /web-app注意servlet-name只是逻辑名由你自己命名它不必和类名相同但必须在servlet-mapping里保持一致。servlet-mapping里的url-pattern是浏览器访问的路径以/开头。定义与映射拆开是web.xml设计的核心思想同一个Servlet可以同时映射到多个URL也可以被不同逻辑名引用。3.2 url-pattern的匹配规则新手最容易在这里翻车url-pattern的匹配规则不是简单的“前缀匹配”它分四类写法匹配范围示例精确匹配只匹配完全相等的路径/hello只匹配/hello路径匹配/某前缀/*匹配指定前缀下所有路径/api/*匹配/api/list、/api/user/1扩展名匹配*.后缀匹配所有以该后缀结尾的路径*.do匹配/user.do默认匹配/匹配所有未被其他模式匹配的路径兜底用这里有两个极易踩的坑。第一个是/与/*完全不同/代表默认Servlet当其他URL匹配不到时交给它通常用来处理静态资源/*则是一网打尽的通配符会把一切请求全部截走包括JSP。新手如果把Servlet映射写成/*访问项目里的JSP页面会直接被这个Servlet接管导致页面显示异常。第二个坑是扩展名匹配不能写成/加后缀比如/*.do是非法的正确的是*.do。如果同时存在精确匹配和通配符匹配容器优先采用精确匹配这是标准的“最长匹配”原则。3.3 init-param与load-on-startup配置里的小机关web.xml里可以在servlet节点内嵌套init-param这些参数会在Servlet实例化后通过ServletConfig传入。比如servlet servlet-namehelloServlet/servlet-name servlet-classcom.demo.HelloServlet/servlet-class init-param param-namegreeting/param-name param-value你好欢迎来到Servlet世界/param-value /init-param load-on-startup1/load-on-startup /servletServlet代码里这样读取String greeting getServletConfig().getInitParameter(greeting);load-on-startup的取值是非负整数数字越小优先级越高。容器启动时会按数字从小到大依次初始化这些Servlet。这个功能常用来预加载核心Servlet或执行某些启动时任务。不过我用个人经验提醒一句尽量不要把重数据库逻辑塞到init()里因为容器启动阶段如果初始化失败可能会导致整个应用无法启动。3.4 metadata-complete这个属性你可能没注意过如果你项目里保留了web.xml且web-app标签上写了metadata-completetrue这是在告诉容器部署描述信息已经完整不要再扫描所有的注解和元数据。这会导致后面要讲的WebServlet注解通通失效。不少同学在旧项目里引入注解后“莫名”404最后查到是旧web.xml里遗留着这个属性。排查思路就是先看web.xml根标签如果是true注解方式的Servlet不会生效需要删掉该属性或改为false。4. 配置方式二WebServlet注解配置与Servlet 3.0之后的变化4.1 注解方式怎么用代码量直接少一半Servlet 3.0对应Tomcat 7及以上版本开始规范支持通过注解声明Servlet我们的web.xml里终于可以不用再写那一大坨了。改造后的Servlet代码看起来更紧凑package com.demo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.WebServlet; import java.io.IOException; WebServlet(name helloServlet, urlPatterns /hello, loadOnStartup 1) public class HelloServlet extends HttpServlet { Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(text/html;charsetUTF-8); response.getWriter().write(h1Hello Servlet by Annotation/h1); } }只要你把类放在应用可扫描的包路径下容器启动时会自动扫描WebServlet注解并注册。原来的web.xml里那一组servlet和servlet-mapping定义就被这一个注解全部代替了。4.2 注解属性的含义与web.xml对照WebServlet支持的主要属性和web.xml里的配置项基本一一对应注解属性对应web.xml配置默认值nameservlet-name类全名如com.demo.HelloServleturlPatterns/valueurl-pattern两者互斥不能同时用空数组loadOnStartupload-on-startup-1表示懒加载initParamsinit-param可写多个空数组asyncSupportedasync-supportedfalsedisplayNamedisplay-name类全名urlPatterns和value二者作用相同但规范上不允许你同时写。写法上建议用urlPatterns可读性更明确比如WebServlet(urlPatterns {/hello, /hi})可以让同一个Servlet对应多个访问路径。4.3 注解方式下的三个常见误区第一个误区以为有了注解就不需要web.xml存在。确实Servlet 3.0后你的动态Web项目可以完全没有web.xml那个web.xml不再是必须文件但如果你要配置欢迎页、全局过滤器顺序、Session超时时间等仍建议保留web.xml它与注解可以共存。第二个误区不做包扫描路径控制。Tomcat启动时默认扫描WEB-INF/classes下所有类的注解如果项目很大注解扫描会拖慢启动速度正式项目往往配置metadata-completefalse或使用其他机制来控制扫描范围。第三个误区修改注解里的URL后不重新编译。注解写在Java源码里它本质是字节码元数据改完注解必须重新编译打包不像web.xml那样改完重启即可生效。这是很多开发者在IDE里改注解却抱怨“没变化”的原因。4.4 顺带一提还有编程式配置这条暗线除web.xml和注解外Servlet还有第三种配置前面虽然没有展开——通过ServletContainerInitializer或ServletContext.addServlet()做编程式注册。这种写法在Spring Boot等框架内部很常见框架不依赖你的web.xml也不依赖遍历注解而是直接在启动时动态注册Servlet。你一般用不到但了解它的存在对理解“一个Servlet到底从哪来”会有帮助。5. 从零跑通一个Servlet Demo两种配置方式完整实践5.1 环境准备和项目骨架实践讲究最小闭环。我的建议是用Maven创建一个war包类型的Web项目装上Tomcat 9对应javax.servlet或Tomcat 10对应jakarta.servlet同时配好IDEA/Eclipse里的Tomcat运行环境。Maven的pom.xml只需要最简依赖dependencies dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency /dependencies注意scope必须是provided因为最终Servlet API由Tomcat提供如果打到war包里反而会冲突。Tomcat 10用户则要把groupId换成jakarta.servletartifactId换成jakarta.servlet-api同时import的包名也从javax.servlet变为jakarta.servlet。这个差异是Java EE移交Eclipse基金会后改的好多人升级Tomcat后疯狂报ClassNotFoundException多半就是包名没换。项目结构servlet-demo/ ├── pom.xml └── src/main/ ├── java/com/demo/UserFormServlet.java └── webapp/ ├── WEB-INF/web.xml └── index.html5.2 写一个带实际业务含义的Servlet表单提交与显示我写一个非常贴近实战的小例子页面显示一个表单收集用户的姓名和城市提交后服务器用动态HTML回显信息。这个例子覆盖了GET、POST、request参数读取、response字符流输出麻雀虽小五脏俱全。package com.demo; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.annotation.WebServlet; import java.io.IOException; WebServlet(name userFormServlet, urlPatterns /form) public class UserFormServlet extends HttpServlet { Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(text/html;charsetUTF-8); PrintWriter out response.getWriter(); out.println(htmlheadtitle用户登记/title/headbody); out.println(h2请输入你的信息/h2); out.println(form actionform methodpost); out.println(姓名input typetext nameusernamebr/); out.println(城市input typetext namecitybr/); out.println(button typesubmit提交/button); out.println(/form/body/html); } Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String city request.getParameter(city); response.setContentType(text/html;charsetUTF-8); PrintWriter out response.getWriter(); out.println(htmlheadtitle结果/title/headbody); out.println(h2你好 username 来自 city /h2); out.println(a hrefform返回/a); out.println(/body/html); } }这个例子最直观的地方在于访问/form用GET返回表单填写后点提交浏览器发的是POST请求同一个Servlet里doGet和doPost各自承担职责。如果你把表单的method改成get提交后你会发现地址栏出现?usernamexxxcityxxx参数被拼到了URL里两种请求方式的差异一目了然。5.3 用两种配置方式分别驱动这个Servlet上面代码里已经有WebServlet注解这是第二种配置方式。为了演示第一种方式我把注解删掉换到web.xml里声明servlet servlet-nameuserFormServlet/servlet-name servlet-classcom.demo.UserFormServlet/servlet-class /servlet servlet-mapping servlet-nameuserFormServlet/servlet-name url-pattern/form/url-pattern /servlet-mapping两种方式跑起来效果完全一致浏览器访问http://localhost:8080/servlet-demo/form都会进入同一个Servlet。区别在于注解方式中URL和类绑定在一起看类就知道路径web.xml中URL和类分离要改映射路径不用动Java代码适合映射关系经常调整的场景。你可以分别配置一次部署两次对比中途URL变化与报错差异这种“亲手切换”比看一百篇对比文章都管用。5.4 验证请求参数与中文显示关于中文这里必须先统一字符编码。POST请求进来获取参数前调用request.setCharacterEncoding(UTF-8)否则getParameter(username)拿到的中文就是乱码。响应写HTML时response.setContentType(text/html;charsetUTF-8)放在getWriter()之前浏览器才能正确解码。我见过很多新手明明代码逻辑都对就是因为漏掉这一行页面上全是问号。6. 实战中绕不开的坑乱码、线程安全、404/405排查与Servlet的现实意义6.1 中文乱码方向不同解法不同中文乱码老实说可以单独写一篇长文。请求方向和响应方向要分开看。响应方向最简单response.setCharacterEncoding(UTF-8)只设置字符流编码再配合response.setContentType(text/html;charsetUTF-8)通知浏览器就不容易乱。请求方向分两种POST请求靠request.setCharacterEncoding(UTF-8)必须在读取任何参数前调用GET请求的参数在URL上由Tomcat解码Tomcat 8及以上版本默认URIEncoding已经是UTF-8老版本则需要在server.xml的Connector上显式配置URIEncodingUTF-8。实际项目里最稳妥的做法是统一让容器层面的过滤器做编码处理这在后续学习Filter时会有更优雅的解法。初学阶段先把请求和响应两侧的编码理解到位。6.2 单实例多线程成员变量非常危险Servlet实例只有一个但所有请求共享这个实例。Tomcat默认用多线程处理并发请求多个线程同时执行同一个实例的方法意味着你写在Servlet类里的成员变量是全局共享的、存在并发问题。举个例子如果你在Servlet里定义了一个int count每次请求自增期望值是“访问了多少次”但并发时由于count不是原子操作你得到的结果往往小于实际请求数。严谨的写法应该是局部变量优先方法内的数据用完就释放如果有跨请求共享状态的需求要么使用ServletContext要么加锁或改用原子类。这个坑在学Servlet时就要种下“线程安全”的意识后面你理解Spring的Bean作用域时会非常受益。6.3 404和405出现时按这几步排查报404首先要分清四种情况应用没启动、访问端口错、路径写错、映射没生效。路径写错最常见比如访问的是/form但web.xml里写的是/userform映射没生效最常见的原因就是前面提到的metadata-completetrue或注解类没有被包扫描覆盖。打开Tomcat的localhost.log看看启动日志写上“Deployment of web application”且无异常基本就排除了部署问题。报405则简单直接请求方式与Servlet支持的方法不匹配。你用GET访问一个只重写了doPost的Servlet会因为父类默认的doGet实现而返回405。另外表单提交后的页面刷新会重复POST有时也容易让人误认为是405问题实际是浏览器在重新提交表单。6.4 都Spring Boot时代了为什么还要学Servlet这个问题我每次带人都要答一遍。Spring Boot看起来是内嵌Tomcat、一个Controller搞定接口可DispatcherServlet本身就是一个ServletSpring MVC的请求处理链完全构建在Servlet规范之上。你不懂Servlet遇到Filter执行顺序的问题会一头雾水写文件下载接口时不知道response流的手动控制逻辑遇到Nginx转发配置也搞不清路径规则从哪来的。Servlet不是要被淘汰的技术它是Java Web的地基。把地基里这两块配置方式吃透后面接触Spring Boot时很多“魔法”都能还原成朴素的技术演进。我在实际带新人的过程中发现最快建立Servlet手感的方法不是直接套Spring Boot写CRUD而是把这个最简单的表单Demo分别用web.xml和注解方式各跑一遍然后故意改错几处改错url-pattern看404不重写doGet看405忘记设置编码看乱码。每个错都自己撞一遍再回头看这篇的所有概念你会觉得整条线一下子通了。下一节可以沿着这个Demo继续加Filter做登录校验或者引入Session保持会话状态基础牢了后面学什么都不慌。

相关新闻

Claude Code与桌面版安装教程:环境配置、VS Code插件及MCP部署

Claude Code与桌面版安装教程:环境配置、VS Code插件及MCP部署

最近一直被同一个问题刷屏:“Claude到底怎么装?”尤其是Claude Code这三个月火起来之后,各大群里问安装的比问用法的还多。我前前后后帮朋友远程装过几十次,也踩了不少坑——什么安装到一半卡死、装完打开白屏、输入命令提示找不到…

2026/10/9 3:31:13 阅读更多 →
JavaWeb调用翻译API的高并发稳定性实践

JavaWeb调用翻译API的高并发稳定性实践

简介:本资源是一份面向JavaWeb初学者与课程设计实践者的在线翻译系统完整实现方案,聚焦API调用、前后端协同与性能优化等核心Web开发能力培养。项目基于ServletJSP构建,集成Cookie前端缓存与Redis后端缓存,支持对接主流翻译API&am…

2026/10/9 3:31:13 阅读更多 →
RabbitMQ测试工具实战:从连通性验证到压测排查的完整指南

RabbitMQ测试工具实战:从连通性验证到压测排查的完整指南

简介:RabbitMQ测试工具是一款基于WPF自编写的消息队列调试应用,面向需要与RabbitMQ打交道的开发者与运维人员,用于解决连接配置、队列浏览、交换机管理、绑定关系可视化及消息收发验证等日常调试需求。资源包共9个文件,以dll动态库…

2026/10/9 3:31:13 阅读更多 →

最新新闻

ASP.NET C# ERP源码二次开发:从部署到改造全流程实战

ASP.NET C# ERP源码二次开发:从部署到改造全流程实战

简介:这是一份面向.NET开发团队的ASP.NET C#大型综合管理系统源码包,定位于大型ERP与全能后台管理系统的项目样板,适合具备一定C#基础、希望直接参考完整工程结构或进行二次开发的中高级开发者。压缩包约52.88MB,以zip格式提供&am…

2026/10/9 4:01:29 阅读更多 →
t3code 整合 Claude Code 与 Codex:Electron 多引擎 AI 编程工具架构解析

t3code 整合 Claude Code 与 Codex:Electron 多引擎 AI 编程工具架构解析

1. 从 t3code 这个标题说起:它到底想解决什么问题第一次看到 “t3code” 这个标题,我脑子里蹦出来的第一个念头是:这大概率又是一个围绕 AI 编程工具做整合或增强的项目。为什么这么判断?因为把标题和它周围那一圈热搜词放在一起看…

2026/10/9 4:01:29 阅读更多 →
Agent-Reach:多Agent协作的触达与编排实战指南

Agent-Reach:多Agent协作的触达与编排实战指南

去年下半年我接手了一个多Agent协作项目,前期单体Agent玩得很溜,结果一上多Agent就翻车——20多个Agent挂在一起互相调用,上午还跑得好好的,下午某几个Agent就开始失联,任务直接在中间环节卡死。折腾了两周&#xff0c…

2026/10/9 4:01:29 阅读更多 →
基于Hadoop和Spark的信贷风控系统架构与落地实践

基于Hadoop和Spark的信贷风控系统架构与落地实践

简介:面向大数据金融信贷风控领域学习者和毕业设计开发者的完整项目源码包,基于Hadoop与Spark技术栈实现信贷风险控制系统,覆盖数据接入、流式处理、风控逻辑及可视化等环节,适合课程设计、毕设或项目初期演示。压缩包内共69个文件…

2026/10/9 4:01:29 阅读更多 →
pstack-claude:本地化进程栈+AI诊断的轻量级系统调试方案

pstack-claude:本地化进程栈+AI诊断的轻量级系统调试方案

1. 项目概述:pstack-claude 是什么,它解决的是哪类开发者的实际痛点?pstack-claude 这个名字乍看像一个工具组合词,但拆解后立刻能抓住核心——它不是某个官方发布的软件包,而是开发者社区中自发形成的一套轻量级本地化…

2026/10/9 4:01:29 阅读更多 →
JavaWeb在线问卷调查系统课程设计:结构部署与核心代码解析

JavaWeb在线问卷调查系统课程设计:结构部署与核心代码解析

简介:基于JavaWeb的在线问卷调查系统课程设计源码包,面向需要完成Java课设、毕设或学习Servlet/JSP与Spring Boot整合开发的学生和开发者。系统覆盖用户注册登录、问卷创建与填写、管理员统一管理、多题型支持(单选、多选、文本题&#xff09…

2026/10/9 4:00:29 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →