新闻详情

新闻详情

首页 / 资讯中心 / 详情

JSP九大内置对象详解:从Servlet源码到实际应用一篇讲透

发布时间:2026/9/30 2:45:42来源:尧图网络
JSP九大内置对象详解:从Servlet源码到实际应用一篇讲透
当年我刚接触JSP时最困惑的一件事就是我明明连import都没写为什么在页面里能用request、session、application这些对象后来翻Tomcat自动生成的Java源码才明白所谓的JSP九大内置对象不过是JSP翻译成Servlet时在_jspService方法里预先帮你声明好的一堆局部变量。这篇文章就围绕九大内置对象的基本使用展开把每个对象是什么类型、什么场景下用、怎么用、为什么这么设计一次性讲清楚。适合还停留在“照抄网上示例”阶段、没搞懂背后原理的初学者也适合要维护老项目、需要快速捡起JSP知识的开发者。1. JSP翻译成Servlet内置对象其实是九个“局部变量”1.1 从_jspService方法看内置对象的出生过程很多人都知道“JSP底层是Servlet”但没亲眼看过那个转换过程。实际上当Tomcat第一次访问一个test.jsp时会把它翻译成test_jsp.java再编译成test_jsp.class。在Tomcat 9的work/Catalina/localhost/应用名/org/apache/jsp目录下你可以直接看到这些生成的Java文件。打开其中一个Java文件核心方法长这样public void _jspService(final HttpServletRequest request, final HttpServletResponse response) throws java.io.IOException, ServletException { ... PageContext pageContext null; HttpSession session null; ServletContext application null; ServletConfig config null; JspWriter out null; Object page this; ... pageContext _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); application pageContext.getServletContext(); config pageContext.getServletConfig(); session pageContext.getSession(); out pageContext.getOut(); ... out.write(html\r\n); }这一小段代码说明了很多东西。request和response是_jspService方法的形参由容器传入。pageContext是九大对象里第一个被创建的对象其余对象基本都是通过pageContext.getXxx()获得的。换句话说内置对象不是“魔法变量”它们有明确的创建顺序和依赖关系容器创建request和response接着创建pageContext再通过pageContext拿到session、application、config、out。理解这一点后很多问题就能想通了。比如为什么在JSP的%! %声明块里不能用request因为声明块里的内容会被编译成Servlet类的成员方法而request只是_jspService方法的局部变量作用域根本不在成员方法内。1.2 九大内置对象的类型与用途速查内置对象真实类型用途requestjavax.servlet.http.HttpServletRequest读取客户端请求参数、请求头、属性转发请求responsejavax.servlet.http.HttpServletResponse设置响应头、响应编码重定向输出响应内容pageContextjavax.servlet.jsp.PageContext页面上下文可访问其它八个对象管理page作用域sessionjavax.servlet.http.HttpSession保存当前用户的会话状态applicationjavax.servlet.ServletContext整个Web应用全局共享的数据outjavax.servlet.jsp.JspWriter向客户端输出内容自带缓冲configjavax.servlet.ServletConfig读取当前Servlet/JSP的初始化参数pagejava.lang.Object实际是this当前JSP对应的Servlet实例基本不用exceptionjava.lang.Throwable仅在isErrorPagetrue的错误页中可用这张表建议存下来。后面讲到的每个对象的坑基本都能在“类型和生命周期”上找到根源。1.3 为什么JSP能直接用Servlet里却不行Servlet里要写request.getParameter()必须先有HttpServletRequest对象而它是service()或doGet()/doPost()方法的参数。JSP里之所以能直接写是因为容器把_jspService()方法里每个局部变量都固定命名为request、response、session……你写的JSP脚本片段会被原样放到这个方法体内当然可以直接引用这些名字。这个设计对初学者很友好但也带来一个负面效果容易让人误以为这些对象是“全局有效的”。实际上它们只在一个_jspService方法调用周期内有效每次请求都会重新创建一套全新的request、response、out等变量。session和application虽然是同一个会话/同一个应用内复用但那是因为它们的底层对象本身生命周期长和局部变量这个名字无关。2. request、response、out三个天天在一起的对象怎么配合2.1 request客户端请求的唯一入口request是最常用的内置对象它封装了浏览器发来的所有信息。读取表单参数是它的核心职责% String username request.getParameter(username); String[] hobbies request.getParameterValues(hobby); MapString, String[] allParams request.getParameterMap(); %getParameter()用于单值参数getParameterValues()用于多选框这类同名多值参数getParameterMap()可以一次拿到所有参数。这里必须区分两个概念参数parameter和属性attribute。参数来自客户端只能读不能写属性是服务端代码放进去的通过setAttribute()写、getAttribute()读。很多初学者把getParameter和getAttribute混用然后在转发时拿不到值其实是因为选错了方法。request还有一个高频操作是请求转发% request.setAttribute(user, userInfo); request.getRequestDispatcher(/userInfo.jsp).forward(request, response); %转发之后目标页面能用request.getAttribute(user)拿到数据因为这次forward是同一个请求在服务端内部的跳转request对象没有换。2.2 response回给浏览器的所有内容都要经过它response负责构建服务端返回给客户端的东西。最基本的两个操作是设置响应类型和重定向% response.setContentType(text/html;charsetUTF-8); response.sendRedirect(login.jsp); %setContentType()必须在真正开始输出内容之前调用。JSP页面里通常通过% page contentTypetext/html;charsetUTF-8 %指令完成这一步容器会自动调用response.setContentType()。这里的charsetUTF-8同时影响响应体的字符编码和浏览器解码方式写漏了最容易出现中文乱码。sendRedirect()就是浏览器重定向服务端会返回一个302状态码和Location响应头浏览器再重新发起一次全新请求。这也是它和forward最本质的区别**一个是一次请求一次响应另一个是两次请求两次响应。**后面第6章会专门讲这个坑。2.3 out自带缓冲的输出流JSP页面默认的写出口out的类型是JspWriter它和response.getWriter()返回的PrintWriter不是同一个东西。JspWriter默认有一个8KB的缓冲区页面里写的内容会先堆积在缓冲区指令执行完了或者缓冲区满了才真正刷到response的输出流里。这样设计是为了减少网络IO次数也能在页面中途发生错误时尽量不输出半截页面。out的基本用法% out.print(pHello/p); out.println(下一行); %表达式% 表达式 %其实也是通过out输出的。模板文本JSP中不是Java代码的普通HTML则由容器生成的out.write(...)来输出。也就是说JSP页面所有写向浏览器的内容最终都汇聚到out这条通道上。2.4 千万别把out和response.getWriter()混在一起写我见过不少维护烂项目的同事在同一个JSP文件里一会儿用out.print()一会儿用response.getWriter().write()结果输出的内容顺序完全不可控。原因就是out有缓冲而response.getWriter()可能直接把内容写到更底层的响应流里两者刷新时机不同先后顺序就会错位。经验法则很简单**JSP页面里一律用outServlet里用response.getWriter()不要混。**如果非要用response.getWriter()输出也要等out的内容主动flush()之后再操作但真没必要这么折腾。3. 状态保存怎么选pageContext、request、session、application四个作用域3.1 四个作用域范围对比JSP里保存数据牵扯到四个对象pageContext、request、session、application。它们对应四个从小到大、从短到长的作用域作用域对应对象存活范围典型场景pagepageContext当前页面处理完成就失效页面内临时变量requestrequest当前请求包含forward转发表单提交结果sessionsession同一个浏览器会话默认30分钟登录状态、购物车applicationapplication整个应用运行期间全局配置、访问次数看到这个表你应该能理解为什么request设置的值在sendRedirect之后拿不到了新的请求产生旧请求已经销毁它的属性自然跟着没了。3.2 pageContext被低估的“对象工具箱”pageContext是九大对象中最特殊的一个因为通过它几乎能拿到其它所有内置对象pageContext.getRequest()、pageContext.getResponse()、pageContext.getSession()、pageContext.getServletContext()、pageContext.getServletConfig()、pageContext.getOut()。所以在自定义标签、JSP片段这类不方便直接声明所有内置对象的地方pageContext就是唯一的入口。它还可以按指定作用域读写数据% pageContext.setAttribute(message, 我在page作用域); pageContext.setAttribute(message, 我在request作用域, PageContext.REQUEST_SCOPE); pageContext.setAttribute(message, 我在session作用域, PageContext.SESSION_SCOPE); pageContext.setAttribute(message, 我在application作用域, PageContext.APPLICATION_SCOPE); // 按顺序查找page → request → session → application String msg (String) pageContext.findAttribute(message); %这里有个非常关键的机制pageContext.findAttribute()会按照page、request、session、application的顺序逐级查找找到第一个就返回。JSP的EL表达式${message}底层用的就是这套查找逻辑。如果不同作用域里存在同名属性EL取到的可能是你没想到的那一个。想精确取值就应该用${requestScope.message}、${sessionScope.message}这样的写法。3.3 session用户的临时状态不能滥用session保存的是同一个浏览器会话内、跨多个请求都能拿到的数据。常见做法是用户登录成功后写入% session.setAttribute(loginUser, username); session.setMaxInactiveInterval(1800); // 30分钟单位秒 %之后其它页面只要从session里取loginUser就知道当前用户是谁。登出时调用session.invalidate()让会话失效同时清空该会话相关数据。session底层依赖Cookie里的JSESSIONID如果客户端禁用了Cookie可以通过response.encodeURL()做URL重写但这会增加实现复杂度。实际应用中浏览器标识一致就认为是同一个会话所以session天然具备“用户隔离”能力。这里要提醒一点不要把大对象、大量List数据塞进session否则每个在线用户都会在服务器内存里占一份用户一多内存很容易被打爆。3.4 application全局共享必须处理并发application对应的ServletContext全局只有一份所有用户共享。最常见的演示案例是统计网站访问次数% Integer count (Integer) application.getAttribute(visitCount); if (count null) { count 0; } count; application.setAttribute(visitCount, count); % p第 % count % 次访问/p但这份代码在多线程并发下有明显的线程安全问题。两个用户同时读到count10各自加1最后可能只变成11。真正的生产代码要么用synchronized包住读写要么直接使用Java的AtomicInteger配合application.setAttribute。如果只是教学演示这个写法没关系放到线上就要小心。3.5 判断标准看这个数据需要活多久我的选择逻辑很固定只在当前JSP页面内用一次用page作用域或普通局部变量需要从Servlet转发到JSP展示用request作用域登录用户、购物车这类跟着用户走的数据放session全局配置项、全局计数器放application。原则是能用小作用域就不用大作用域。数据能放request绝不放session能放session绝不放application。作用域越大内存压力越大数据错乱的可能性也越大。4. 存在感很低的config、page、exception三个对象4.1 config读取JSP初始化参数config是ServletConfig类型在JSP里最主要的用途就是读取初始化参数。少数老项目会把某些业务配置放到web.xml里给某个JSP单独设置参数servlet servlet-nameconfigDemo/servlet-name jsp-file/configDemo.jsp/jsp-file init-param param-namepublisher/param-name param-value张三/param-value /init-param /servlet servlet-mapping servlet-nameconfigDemo/servlet-name url-pattern/configDemo.jsp/url-pattern /servlet-mapping然后在JSP里读% String publisher config.getInitParameter(publisher); out.println(发布者 publisher); %这套机制相当于把页面内容和运行参数解耦。不过现在的项目里参数更多放在数据库或配置中心这个对象的使用频率已经很低了。但看到老代码不要慌要认得它。4.2 page九大对象里最容易被人无视的一个page指向当前JSP翻译出来的Servlet实例本质就是this。在Tomcat生成的源码里有一句Object page this;。由于JSP里很少需要直接操作Servlet实例本身所以page在正常开发中用不上。唯一有点存在感的场景是在模板JSP中通过反射获取当前Servlet信息比如page.getClass().getName()或者判断当前Servlet是否实现了某个接口。我见过一些旧项目里用% page.toString() %调试能拿到类似org.apache.jsp.index_jspxxxx的输出。这算是一个隐藏调试技巧但不要指望它能做太多事情。4.3 exception只在错误页里活着的对象exception和其它八个对象最大的区别在于**它不是每个页面都能用只有% page isErrorPagetrue %的页面才能用。**想在普通页面用exception编译阶段就会报“exception cannot be resolved”。使用方式分为两步。先在一个普通页面声明错误页% page errorPageerror.jsp % % int result 10 / 0; %当页面抛出未捕获异常后容器会跳到error.jsp。在错误页里用exception拿到异常信息% page isErrorPagetrue % html headtitle错误页/title/head body h3系统出了点问题/h3 p错误信息% exception.getMessage() %/p /body /html也可以去掉errorPage属性改成在web.xml里配置全局错误页error-page exception-typejava.lang.Throwable/exception-type location/error.jsp/location /error-page这会作用于整个应用。需要特别注意的是生产环境的错误页绝对不要直接打印exception.printStackTrace()或者把完整堆栈输出给用户。这些信息很容易暴露代码结构、数据库类型等敏感细节。正确做法是把完整堆栈记录到日志页面上只展示一句友好提示。5. 用一个个人信息展示页面把九大内置对象串起来实践5.1 场景说明这一章我们做一个最简单的“个人信息展示”页面。用户先填一个表单提交姓名、城市、爱好第二个JSP页面负责展示同时用session记录当前用户用application记录总访问次数。这样能把request、response、out、session、application、pageContext全都串起来跑一遍。这个场景也可以直接改造成学生信息管理系统里“学生信息展示”的雏形。5.2 IDEA里创建JSP文件的注意点在IntelliJ IDEA中新建infoInput.jsp时默认生成的模板第一行是% page contentTypetext/html;charsetUTF-8 languagejava %这里要注意IDEA里JSP文件本身的编码设置。右下角File Encoding如果是GBK而contentType里声明的是UTF-8必然乱码。我刚入职的时候在这个问题上栽过跟头建议在IDEA的Settings里把Editor File Encodings的Default encoding统一改成UTF-8创建JSP前先确认右下角编码。5.3 表单页收集个人信息infoInput.jsp的代码% page contentTypetext/html;charsetUTF-8 languagejava % html headtitle个人信息提交/title/head body h3请填写个人信息/h3 form actionuserInfo.jsp methodpost p姓名input typetext nameusername//p p城市 select namecity option value北京北京/option option value上海上海/option option value广州广州/option /select /p p爱好 labelinput typecheckbox namehobbies valueJava/Java/label labelinput typecheckbox namehobbies valueReading/Reading/label labelinput typecheckbox namehobbies valueMusic/Music/label /p input typesubmit value提交/ /form /body /html这里用methodpost而不是get有两个原因一是避免中文参数直接暴露在URL里二是表单内容可能很长GET方式有URL长度限制POST没有。5.4 展示页配合request、session、application使用userInfo.jsp的代码% page contentTypetext/html;charsetUTF-8 languagejava % % request.setCharacterEncoding(UTF-8); String username request.getParameter(username); String city request.getParameter(city); String[] hobbies request.getParameterValues(hobbies); if (username null || username.trim().isEmpty()) { response.sendRedirect(infoInput.jsp); return; } request.setAttribute(city, city); session.setAttribute(currentUser, username); Integer visitCount (Integer) application.getAttribute(visitCount); if (visitCount null) { visitCount 0; } visitCount; application.setAttribute(visitCount, visitCount); % html headtitle% username %的个人信息/title/head body h3% username %你好欢迎回来/h3 p当前访问次数% visitCount %/p p所在城市% request.getAttribute(city) %/p p兴趣爱好/p ul % if (hobbies ! null) { for (String hobby : hobbies) { out.println(li hobby /li); } } else { out.println(li无/li); } % /ul p会话ID% session.getId() %/p /body /html代码里有几个细节值得解释。第一request.setCharacterEncoding(UTF-8)必须出现在任何getParameter()之前如果先读了参数再设置编码POST请求体已经按ISO-8859-1解析完再设置就晚了。第二request.getParameterValues(hobbies)返回的是String数组没有选择任何爱好时返回null所以要做空判断。第三response.sendRedirect(infoInput.jsp); return;这两行缺一不可return保证后面的页面代码不再执行否则即使跳转状态已经发出容器仍可能继续渲染空页面。5.5 登录状态的简单控制在其它页面里可以这样判断用户是否已经提交过信息% Object loginUser session.getAttribute(currentUser); if (loginUser null) { response.sendRedirect(infoInput.jsp); return; } %这就是学生信息管理系统中常见的登录校验雏形但注意真实项目不要在每个JSP里复制这段代码应该用Filter统一处理。JSP内置对象让你能快速写通功能但工程化时要控制散落各处的重复脚本。5.6 去Tomcat的work目录看编译后的Java类这部分对应很多人搜过的“查看JSP编译后的java类”。在应用的运行目录下找到apache-tomcat-9.0.xx/work/Catalina/localhost/你的应用名/org/apache/jsp/userInfo_005finput_jsp.java文件名里的_005f是下划线转义。打开这个文件就能看到_jspService方法里完整的对象初始化逻辑以及你写的HTML和脚本变成的Java代码。我建议每个学JSP的人都去翻一次这个目录看完之后对内置对象、脚本片段、表达式的关系会有一种豁然开朗的感觉。6. 内置对象使用时最常见的几个坑6.1 转发和重定向request作用域失效的根源这是新手最容易踩的坑。在Servlet或JSP里写了% request.setAttribute(msg, 转发测试); request.getRequestDispatcher(result.jsp).forward(request, response); %result.jsp里用request.getAttribute(msg)能拿到值因为全程只有一次请求。如果改成% session.setAttribute(msg, 重定向测试); response.sendRedirect(result.jsp); %result.jsp里用request.getAttribute(msg)就一定拿到null因为第二次请求是浏览器重新发起的和第一次请求没有任何关系。正因为这一点我习惯把两者的区别记成一句话**forward是服务端把活干完再回应给浏览器浏览器全程只发了一次请求sendRedirect是服务端告诉浏览器“你去找另一个地址”浏览器重新发一次请求。**项目里如果用了Spring MVC的return forward:xxx和return redirect:xxx底层也是同一套逻辑。6.2 乱码setCharacterEncoding的时间窗口问题中文乱码算是JSP时代最常见的坑了而且表现五花八门。第一种是POST表单提交乱码解决方式就是在接收页面里第一个做% request.setCharacterEncoding(UTF-8); %必须放在所有getParameter调用之前。第二种是响应输出乱码解决方式是用page指令声明% page contentTypetext/html;charsetUTF-8 languagejava %这句话会让容器调用response.setContentType(text/html;charsetUTF-8)。第三种是JSP文件本身编码不对文件保存成GBK却在page指令里写UTF-8或者反过来这样页面上所有中文都是乱码。这个坑IDE里最容易遇到检查顺序应该是文件编码、pageEncoding、contentType、浏览器请求头。GET请求的乱码相对特殊。Tomcat 8及以上默认使用UTF-8解析URI中的参数所以一般不会乱老版本Tomcat需要在server.xml的Connector上配置URIEncodingUTF-8。搜“jsp乱码”能看到大量相关文章其实就是这几种情况。6.3 session和application的数据串台session是按用户隔离的application是全局共享的这个很多人知道但代码里不一定分得清。最典型的错误是% session.setAttribute(userInfo, user); %如果在跨用户场景下不小心用了application.setAttribute(userInfo, user)那么用户A提交的数据会被用户B覆盖B刷新后甚至看到A的信息。这类“串数据”问题排查起来特别隐蔽因为它不是必现的只有并发访问时才会暴露。另一个容易被忽略的问题是session里的数据不会自动消失会一直占用内存直到会话过期。如果把一个十几MB的临时查询结果随手setAttribute进session每个在线用户都占一份服务器内存很快告急。我的建议是能被request带的就别放session能重建的临时数据就别缓存。6.4 EL表达式的查找顺序会骗人EL表达式${username}的查找顺序和pageContext.findAttribute()完全一致page → request → session → application。假设你在request里放了username张三又在session里放了username李四EL表达式会先命中request输出“张三”。这个行为本身是规范的但很容易让初学者困惑为什么我session里明明改了值页面上展示的还是旧值解决方式是避免同名属性散落多个作用域或者在EL表达式里显式指定作用域${requestScope.username}、${sessionScope.username}。搜索引擎里那些“EL表达式取不到值”的问题至少有一半和这个查找顺序有关。6.5 在%! %声明块里使用内置对象导致编译失败我已经不止一次看到新人在%!块里写%! private String getClientIp() { return request.getRemoteAddr(); // 编译报错request cannot be resolved } %原因在前面说了%! %里的代码会成为Servlet类的成员方法request只是_jspService方法的局部变量成员方法里根本看不到它。正确做法是把request作为参数传进这个方法%! private String getClientIp(HttpServletRequest request) { return request.getRemoteAddr(); } %这个小细节能帮你避免一次莫名其妙的编译错误。6.6 用全局错误页时exception不显示有些项目配置了web.xml的全局错误页但发现页面里% exception %一直编译报错。这是因为全局错误页也要满足两个条件isErrorPagetrue和错误页本身能被容器识别为错误处理页面。如果你在JSP里没有加% page isErrorPagetrue %exception对象就不会被注入。加上之后再配合web.xml的error-page配置才能正常使用。另外如果错误页本身也抛异常会形成错误处理循环Tomcat最终会展示它自己的默认错误页。7. 关于JSP内置对象的个人经验和建议最后分享一些我个人在项目里积累的体会。维护老项目时内置对象是理解页面的钥匙。看到一个老JSP页面先扫一遍它用了哪些内置对象基本就能猜出页面逻辑用了session多半涉及登录态用了application多半有全局统计用了request.getAttribute多半前面有Servlet转发。这种“通过内置对象反推架构”的能力对接手老系统特别有用。写新代码时我的建议是不要让JSP承担太多Java逻辑。现在的前后端开发模式里JSP更多是充当模板控制逻辑放在Servlet或Spring MVC的Controller中。页面里尽量少写% %脚本多用EL表达式和JSTL让request、session、application只承担传递数据的作用而不是写一堆循环和判断。这样既好维护也容易迁移到更现代的模板技术。学习阶段一定要去Tomcat的work目录看一次生成的Java文件。很多教程讲了半天“JSP的本质是Servlet”都不如你亲眼看到_jspService方法里那九个变量是怎么声明、怎么赋值的。看完那一页源码你对request、response、out、pageContext这些对象的理解会完全不同。还有个记忆技巧九个内置对象可以分成三组来记——request、response是HTTP请求响应的两端out是页面输出通道pageContext、session、application、config、page是一组和Servlet上下文、会话、配置、实例相关的对象exception单独记它只在错误页出现。分组之后考试也好、翻代码也好都不容易漏。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

doocs/leetcode 插入排序(Insertion Sort)算法详解:动态有序插入思想与多语言实现 2026/9/30 6:39:31

doocs/leetcode 插入排序(Insertion Sort)算法详解:动态有序插入思想与多语言实现

示例工程教程 【免费下载链接】leetcode 🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解 项目地址: https:/…

阅读更多 →
怎么在 Switch 上跑 wiliwili 看B站 2026/9/30 6:39:31

怎么在 Switch 上跑 wiliwili 看B站

怎么在 Switch 上跑 wiliwili 看B站 【免费下载链接】wiliwili 第三方B站客户端,目前可以运行在PC全平台、PSVita、PS4 、Xbox 和 Nintendo Switch上 项目地址: https://gitcode.com/GitHub_Trending/wi/wiliwili 游戏通关的空档想在 Switch 上刷两集B站&…

阅读更多 →
Flipper Zero Unleashed 固件 FAP 插件安装完整指南:3 条路径覆盖 SD 卡、fbt 与 WiFi 模块 2026/9/30 6:39:30

Flipper Zero Unleashed 固件 FAP 插件安装完整指南:3 条路径覆盖 SD 卡、fbt 与 WiFi 模块

Flipper Zero Unleashed 固件 FAP 插件安装完整指南:3 条路径覆盖 SD 卡、fbt 与 WiFi 模块 【免费下载链接】unleashed-firmware Flipper Zero Unleashed Firmware 项目地址: https://gitcode.com/GitHub_Trending/un/unleashed-firmware Flipper Zero Unle…

阅读更多 →
Claude 环境下的 MCP Server 鉴权完全指南:从 CIMD/DCR 选型到 Token 存储与 SDK 落地 2026/9/30 6:39:24

Claude 环境下的 MCP Server 鉴权完全指南:从 CIMD/DCR 选型到 Token 存储与 SDK 落地

AI 插件开发工具插件系统 【免费下载链接】claude-plugins-official Official, Anthropic-managed directory of high quality Claude Code Plugins. 项目地址: https://gitcode.com/GitHub_Trending/cl/claude-plugins-official 点击查看 免费下载 在 Claude 生态…

阅读更多 →
YuE2 白盒音乐生成指南:用 ABC 乐谱编辑 AI 生成的歌曲,改和弦、换歌词、变速度全都能做到 2026/9/30 6:39:24

YuE2 白盒音乐生成指南:用 ABC 乐谱编辑 AI 生成的歌曲,改和弦、换歌词、变速度全都能做到

YuE2 白盒音乐生成指南:用 ABC 乐谱编辑 AI 生成的歌曲,改和弦、换歌词、变速度全都能做到 【免费下载链接】YuE YuE2: frontier music generation with symbolic planning, zero-shot covers, and agentic music editing. 项目地址: https://gitcode.…

阅读更多 →
Liquibase 数据库变更管理快速上手指南:5 分钟跑通第一次数据库迁移 2026/9/30 6:39:24

Liquibase 数据库变更管理快速上手指南:5 分钟跑通第一次数据库迁移

Liquibase 数据库变更管理快速上手指南:5 分钟跑通第一次数据库迁移 【免费下载链接】liquibase Main Liquibase Source 项目地址: https://gitcode.com/GitHub_Trending/li/liquibase Liquibase 是一款广泛使用的开源数据库变更管理工具。它让数据库结构改动…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉