Spring boot + SpringMVC Web + Thymeleaf(IDEA多模块项目)

Spring Boot干货系列:(四)开发Web应用之Thymeleaf篇

 

Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用。它的功能特性如下:

  • Spring MVC中@Controller中的方法可以直接返回模板名称,接下来Thymeleaf模板引擎会自动进行渲染
  • 模板中的表达式支持Spring表达式语言(Spring EL)
  • 表单支持,并兼容Spring MVC的数据绑定与验证机制
  • 国际化支持

Spring官方也推荐使用Thymeleaf,所以本篇代码整合就使用Thymeleaf来整合。

 

 

引入依赖

引入Thymeleaf的依赖

复制代码
 1 <!--WEB支持-->
 2         <dependency>
 3             <groupId>org.springframework.boot</groupId>
 4             <artifactId>spring-boot-starter-web</artifactId>
 5         </dependency>
 6  <!--thymeleaf-->
 7         <dependency>
 8             <groupId>org.springframework.boot</groupId>
 9             <artifactId>spring-boot-starter-thymeleaf</artifactId>
10         </dependency>
11 <!--thymeleaf layout-->
12         <dependency>
13             <groupId>nz.net.ultraq.thymeleaf</groupId>
14             <artifactId>thymeleaf-layout-dialect</artifactId>
15         </dependency>
16 <!-- 允许使用非严格的 HTML 语法 -->
17         <dependency>
18             <groupId>net.sourceforge.nekohtml</groupId>
19             <artifactId>nekohtml</artifactId>
20             <version>1.9.22</version>
21         </dependency>
pom.xml
复制代码

设置Thymeleaf属性

复制代码
 1 # thymeleaf
 2 spring.thymeleaf.prefix=classpath:/templates/
 3 spring.thymeleaf.check-template-location=true
 4 spring.thymeleaf.suffix=.html
 5 spring.thymeleaf.encoding=UTF-8
 6 spring.thymeleaf.servlet.content-type=text/html
 7 # 用非严格的 HTML
 8 spring.thymeleaf.mode=HTML
 9 # 开发时关闭缓存,不然没法看到实时页面
10 spring.thymeleaf.cache=false
application.properties
复制代码

 

注意:Program.java类文件里面已经没有关于servlet的配置了。

复制代码
 1 package tb.view.sbmsm.easyuidemo;
 2 
 3 import org.mybatis.spring.annotation.MapperScan;
 4 import org.springframework.boot.SpringApplication;
 5 import org.springframework.boot.autoconfigure.SpringBootApplication;
 6 
 7 @SpringBootApplication(scanBasePackages = {"tb.view.sbmsm.easyuidemo"})
 8 @MapperScan(basePackages = "tb.db.mysql.shopcart.mybatis")
 9 public class Program {
10 
11     public static void main(String[] args) {
12         SpringApplication.run(Program.class, args);
13     }
14 
15 }
Program.java
复制代码

 

 Index.html

复制代码
 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th=”http://www.thymeleaf.org“ >
 3 <head>
 4     <meta charset="UTF-8">
 5     <title th:text="#{WEB_SITE_NAME}"></title>
 6 </head>
 7 <body>
 8     <h1>Hello World</h1>
 9     <h2 th:text="${Email}"></h2>
10     <hr/>
11     <h3 th:text="${UserDir}"></h3>
12 </body>
13 </html>
Index.html
复制代码

 

引入依赖后就在默认的模板路径src/main/resources/templates下编写模板文件即可完成。这里我们新建一个HelloWorld.html:

注:通过xmlns:th=”http://www.thymeleaf.org“ 命令空间,将静态页面转换为动态的视图,需要进行动态处理的元素将使用“th:”前缀。

 

教程:使用Thymeleaf

 

Thymeleaf佈局layout

 

 

复制代码
 1 <!DOCTYPE html>
 2 <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
 3     <head th:fragment="Head(Title, Header)">
 4         <title th:replace="${Title}">EasyUI Demo</title>
 5         <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 6         <meta name="viewport" content="width=device-width" />
 7         <meta name="renderer" content="webkit">
 8         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
 9         <meta http-equiv="imagetoolbar" content="no">
10         <link href="/favicon.ico" rel="shortcut icon" type="image/x-icon" />
11         <link href="/favicon.ico" rel="icon" type="image/x-icon" />
12 
13         <link href="/Content/TB/reset.css" rel="stylesheet" />
14         <link href="/Content/jquery.easyUI/1.5.1/themes/gray/easyui.css" rel="stylesheet" type="text/css" id="themes" />
15         <link href="/Content/jquery.easyUI/1.5.1/themes/icon.css" rel="stylesheet" />
16         <link href="/Content/TB.Behind/form.css" rel="stylesheet" />
17         <link href="/Content/TB.Behind/fix.css" rel="stylesheet" />
18         <link href="/Content/TB.Behind/TB.Behind.css" rel="stylesheet" />
19 
20         <script src="/Content/jquery/1.x/jquery-1.8.2.js" language="javascript" type="text/javascript"></script>
21         <script src="/Content/jquery.plugins/jquery.cookie.js" language="javascript" type="text/javascript"></script>
22         <script src="/Content/jquery.plugins/jquery.media.js" language="javascript" type="text/javascript"></script>
23 
24         <script src="/Content/jquery.easyUI/1.5.1/jquery.easyui.min.js" language="javascript" type="text/javascript"></script>
25         <script src="/Content/jquery.easyUI/1.5.1/locale/easyui-lang-zh_CN.js" language="javascript" type="text/javascript"></script>
26         <script src="/Content/jquery.easyUI/1.5.1/jquery.easyui.extensions.js" language="javascript" type="text/javascript"></script>
27 
28         <script src="/Content/TB/TB.js" language="javascript" type="text/javascript"></script>
29         <script src="/Content/TB.Behind/TB.Behind.js" language="javascript" type="text/javascript"></script>
30         <script src="/Content/TB/fix.js" language="javascript" type="text/javascript"></script>
31 
32         <th:block th:replace="${Header}" />
33     </head>
34 
35     <!--BODY START-->
36     <th:block layout:fragment="Body" />
37     <!--BODY END-->
38     <!--Footer START-->
39     <th:block layout:fragment="Scripts"/>
40     <!--Footer END-->
41 
42 </html>
_Layout.html
复制代码

 

复制代码
  1 <!DOCTYPE html>
  2 <html xmlns:th="http://www.thymeleaf.org"
  3       xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
  4 <head th:replace="Shared/_Layout :: Head(~{this :: title}, ~{this :: .custom-Header})" >
  5     <title th:text="${WEB_SITE_NAME}"></title>
  6     <!--脚本引入区域-->
  7     <style class="custom-Header">
  8         html, body {
  9             height: 100%;
 10             overflow: hidden;
 11         }
 12     </style>
 13     <script class="custom-Header" src="/Content/TB/TB.Hock.js"></script>
 14     <script class="custom-Header" src="/Content/jquery.easyUI/extend/tree_search.js" language="javascript" type="text/javascript"></script>
 15 </head>
 16 <body class="easyui-layout">
 17     <th:block layout:fragment="Body">
 18         <!--左边菜单-->
 19         <div data-options="region:'west',title:'菜单目录',split:true" style="width: 200px;position:relative;">
 20             <input type="text" id="search" autocomplete="off" data-options="prompt: '菜单搜索'" style="height: 20px; width: 97%; ime-mode: active" class="easyui-validatebox" />
 21             <ul id="leftMenu"></ul>
 22         </div>
 23         <div data-options="region:'center',split:true">
 24             <div id="tab" class="easyui-tabs">
 25                 <div data-options="title:'首页',iconCls:'icon-home',closable:false,iniframe:true,href:'/Home/Welcome/',fit:true" style="overflow: hidden;">
 26                 </div>
 27             </div>
 28         </div>
 29         <!--底-->
 30         <div data-options="region:'south',title:'',split:false" style="height: 33px; overflow: hidden;">
 31             <table style="width: 100%;">
 32                 <tr>
 33                     <td style="width: 200px; text-align: left;"><span style="line-height: 25px;">版本:@Html.Raw(ViewBag.AssemblyVersion)</span></td>
 34                     <td style="width: auto; text-align: center;"><span style="line-height: 25px;">版权:北京踏浪者科技有限公司</span></td>
 35                     <td style="width: 306px; text-align: left;">
 36                         <table style="width: 100%;">
 37                             <tr>
 38                                 <td>
 39                                     <a class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-logout'" href="/Auth/Logout/" id="exit" name="exit" title="注销登陆"></a>
 40                                     <a class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-edit'" id="updatePwd" name="updatePwd" title="修改密码"></a>
 41                                     <a class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-zoom'" id="btnFullScreen" name="btnFullScreen" title="全屏模式切换"></a>
 42                                 </td>
 43                                 <td>
 44                                     <div class="datagrid-btn-separator"></div>
 45                                     <span style="line-height: 25px;">页面主题:</span><select id="themeSelector"></select>
 46                                 </td>
 47                             </tr>
 48                         </table>
 49                     </td>
 50                 </tr>
 51             </table>
 52         </div>
 53     </th:block>
 54 
 55     <th:block layout:fragment="Scripts">
 56         <script type="text/javascript">
 57             $("#themeSelector").combobox({
 58                 width: 140, editable: false, data: $.easyui.theme.themes,
 59                 value: $.easyui.theme.get(),
 60                 onSelect: function (record) {
 61                     $.easyui.theme.change(record.value);
 62                 }
 63             });
 64             window.tabPages = $('#tab').tabs({
 65                 border: false,
 66                 fit: true,
 67                 enableConextMenu: true,
 68                 lineHeight: 0
 69             });
 70             //TB.hock.tabs.dragTab('#tab');
 71 
 72             //   /Home/GetMenuData
 73             $("#leftMenu").tree({
 74                 method: "post",
 75                 lines: true,
 76                 url: "",
 77                 smooth: true,
 78                 checkbox: false,
 79                 toggleOnClick: true,
 80                 onClick: function (node) {
 81                     TB.tabShow(node.text, node.attributes, node.iconCls);
 82                 },
 83                 onCollapse: function (node) {
 84                     if (node.id == "00000000-0000-0000-0000-000000000000") {
 85                         $(this).tree("collapseAll");
 86                     }
 87                 },
 88                 //onLoadSuccess: function (node) {
 89                 //    $(this).tree("collapseAll");
 90                 //    $('#left_menu').find('[node-id=00000000-0000-0000-0000-000000000000]').click();
 91                 //}
 92             });
 93 
 94             $("#btnFullScreen").click(function () {
 95                 if (TB.fullScreen.supports) {
 96                     if (TB.fullScreen.isFullScreen()) {
 97                         TB.fullScreen.cancel();
 98                     } else {
 99                         TB.fullScreen.request();
100                     }
101                 } else {
102                     TB.error("当前浏览器不支持全屏 API,请更换至最新的 Chrome/Firefox/Safari 浏览器或通过 F11 快捷键进行操作。");
103                 }
104             });
105             //修改密码
106             $('#updatePwd').on("click", function () {
107                 TB.dialog({
108                     title: "修改密码",
109                     width: 400,
110                     height: 300,
111                     href: "/Auth/ChangePassword",
112                     iframe: true,
113                     buttons: [{
114                         text: '确定',
115                         iconCls: 'icon-ok',
116                         handler: function (dialog, iframe) {
117                             top.window.location.replace("/Auth/Logout/");
118                         }
119                     }]
120                 });
121             });
122             $(function () {
123                 $("#search").on("keyup",function() {
124                     $("#leftMenu").tree("search", $(this).val());
125                     if ($(this).val() === "" || null == $(this).val()) {
126                         $('#left_menu').tree("expandAll");
127                     }
128                     return true;
129                 });
130             });
131         </script>
132     </th:block>
133 </body>
134 
135 </html>
Index.html
复制代码

 

复制代码
  1 <!DOCTYPE html>
  2 <html xmlns:th="http://www.thymeleaf.org"
  3       xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
  4 <head th:replace="Shared/_Layout :: Head(~{this :: title}, ~{this :: .custom-Header})" >
  5     <title></title>
  6 <style class="custom-Header">
  7     * {
  8         font-size: 12px;
  9         padding: 0;
 10         margin: 0;
 11     }
 12 
 13     .panel-body {
 14         overflow: initial;
 15         padding: 5px;
 16     }
 17 
 18     .panel {
 19         margin-bottom: 5px;
 20     }
 21 
 22     .ver {
 23         width: 100%;
 24         overflow: hidden;
 25     }
 26 
 27     .ver li {
 28         display: block;
 29         position: relative;
 30         width: 100%;
 31         padding: 10px 0;
 32     }
 33 
 34     .ver li:before {
 35         display: block;
 36         position: absolute;
 37         left: 80px;
 38         width: 2px;
 39         height: 100%;
 40         background-color: #ccc;
 41         content: '';
 42     }
 43 
 44     .ver li:after {
 45         display: block;
 46         position: absolute;
 47         top: 26px;
 48         left: 74px;
 49         width: 15px;
 50         height: 15px;
 51         border-radius: 50%;
 52         background-color: #999;
 53         content: '';
 54     }
 55 
 56     .ver .ver-left {
 57         display: block;
 58         position: absolute;
 59         width: 70px;
 60         padding-top: 13px;
 61         padding-right: 10px;
 62         font-size: 14px;
 63         text-align: right;
 64         color: #999;
 65     }
 66 
 67     .ver .ver-right {
 68         display: block;
 69         position: relative;
 70         margin-left: 100px;
 71         padding: 8px;
 72         border-radius: 3px;
 73         border: solid 1px #ccc;
 74         background-color: #FaFaFa;
 75     }
 76 
 77     .ver .ver-right:after {
 78         display: block;
 79         position: absolute;
 80         top: 16px;
 81         left: -6px;
 82         width: 0;
 83         height: 0;
 84         content: '';
 85         border-top: 6px solid transparent;
 86         border-right: 6px solid #ccc;
 87         border-bottom: 6px solid transparent;
 88     }
 89 
 90     .ver .ver-title {
 91         padding: 0 5px 5px 5px;
 92         font-size: 14px;
 93         border-bottom: 1px solid #ccc;
 94     }
 95 
 96     .ver .ver-title code {
 97         font-weight: bold;
 98         font-style: normal;
 99     }
100 
101     .ver .ver-content {
102         display: block;
103         padding: 5px 0;
104         line-height: 20px;
105     }
106     /*.ver li:first-child:after { background-color: #000;}*/
107 </style>
108 <link class="custom-Header" href="/Content/TB/TB.Task.css" rel="stylesheet" />
109 </head>
110 <body>
111 <th:block layout:fragment="Body">
112 <div style="padding: 5px;">
113     <div class="easyui-panel" data-options="collapsible:true,fit:false" style="width:100%">
114         <div style="padding: 5px;">尊敬的<b> @Model </b>,您好!欢迎使用踏浪者DEMO系统。</div>
115     </div>
116     <div class="easyui-panel" title="SnowFlake全局唯一ID及工具类" data-options="collapsible:true,fit:false" style="width:100%">
117         <a href="https://www.cnblogs.com/relucent/p/4955340.html">雪花构建全局唯一ID:</a><b>@ViewBag.GlobalID</b>
118     </div>
119     <div class="easyui-panel" title="扫码枪Demo" data-options="collapsible:true,fit:false" style="width:100%">
120         <div data-options="border:false" style="overflow: hidden; background-color: #f0f0f0;">
121             <div style="height: 80px; overflow: hidden;">
122                 <input id="input" class="scanbox" placeholder="请扫描包裹号" />
123             </div>
124         </div>
125     </div>
126     <div class="easyui-panel" title="账户信息" data-options="collapsible:true,fit:false" style="width:100%">
127         <div id="user-info">
128             正在拉取数据...
129         </div>
130         <script type="text/template" id="user-info-template">
131             <ul>
132                 <li>登录账户:{{ LoginAccount}}</li>
133                 <li>登录IP:{{ LoginIP}}</li>
134                 <li>联系电话:{{ Phone}}</li>
135                 <li>账户状态:{{ Status}}</li>
136                 <li>所属权限组:{{ GroupText}}</li>
137                 <li>所属角色组:{{ RoleText}}</li>
138             </ul>
139         </script>
140     </div>
141     <div class="easyui-panel" title="更新内容(最近5次)" data-options="collapsible:true,fit:false" style="width:100%">
142         <div id="ver">
143             正在拉取数据...
144         </div>
145         <script type="text/template" id="ver-template-item">
146             {{each list as item}}
147             <li>
148                 <div class="ver-left">{{ item.Time}}</div>
149                 <div class="ver-right">
150                     <div class="ver-title">
151                         <code>v{{ item.Version}}</code>&nbsp;{{ item.Title}}&nbsp;&nbsp;{{# item.IsNew==true?"<img src='/Content/Images/new.gif' alt='new' style='vertical-align: middle;' />":"" }}
152                     </div>
153                     <div class="ver-content">{{# item.Content}}</div>
154                 </div>
155             </li>
156             {{/each}}
157             <li>
158                 <div class="ver-left">更早</div>
159                 <div class="ver-right">
160                     <div class="ver-content"><a href="javascript:void(0);" onclick="TB.tabShow('更新记录', '/Basis/Version/VersionView');">查看更多</a></div>
161                 </div>
162             </li>
163 
164         </script>
165     </div>
166     <div class="easyui-panel" title="EasyUI官网" data-options="collapsible:true,fit:false" style="width:100%">
167         <a href="http://www.jeasyui.com/" target="_blank">http://www.jeasyui.com/</a>
168     </div>
169     <div class="easyui-panel" title="常用操作" data-options="collapsible:true,fit:false" style="width:100%">
170         <div id="ver">
171             <button class="easyui-linkbutton" id="dig-alert">alert</button>
172             <button class="easyui-linkbutton" id="dig-warn">warn</button>
173             <button class="easyui-linkbutton" id="dig-info">info</button>
174             <button class="easyui-linkbutton" id="di-show">show</button>
175             <button class="easyui-linkbutton" id="di-dialog">dialog</button>
176             <button class="easyui-linkbutton" id="di-confirm">confirm</button>
177             <button class="easyui-linkbutton" id="di-wait">wait</button>
178             <button class="easyui-linkbutton" id="di-open">open</button>
179             <button class="easyui-linkbutton" id="di-api">api</button>
180             <button class="easyui-linkbutton" id="di-task">task</button>
181             <button class="easyui-linkbutton" id="di-notity">notity</button>
182         </div>
183     </div>
184 </div>
185 <a class="media"></a>
186 </th:block>
187 <th:block layout:fragment="Scripts">
188 <script src="/Content/jquery.plugins/jquery.media.js"></script>
189 <script src="/Content/TB/TB.scanbox.js"></script>
190 <script src="/Content/TB/TB.Task.min.js"></script>
191 <script src="/Content/TB/TB.Notity.min.js"></script>
192 <script type="text/javascript">
193     $('[id^=dig]').on('click', function () {
194         //TB.alert();
195         //TB.warn();
196         //
197         TB[$(this).text()]("测试消息");
198     });
199     $('#di-show').on('click', function () {
200         //TB.show(content, title, icon, position, timeout);
201         TB.show("测试消息", "xxxx");
202     });
203     $('#di-dialog').on('click', function () {
204         TB.dialog({
205             title: "添加站点",
206             width: 500,
207             height: 420,
208             modal: true,
209             href: "http://www.baidu.com",
210             iframe: true,
211             buttons: [{
212                 text: '确定',
213                 iconCls: 'icon-ok',
214                 handler: function (dialog, iframe) {
215                     //iframe.contentWindow.save(function () {
216                     //    cache.view.datagrid('reload');
217                     //    dialog.dialog('close');
218                     //});
219 
220                     TB.alert("确定");
221                 }
222             }]
223         });
224     });
225     $('#di-confirm').on('click', function () {
226         TB.confirm("测试消息", function (r) {
227 
228             //r==true/false
229         });
230     });
231     $('#di-wait').on('click', function () {
232         TB.wait("测试消息");
233         setTimeout(function () {
234             TB.wait(null);
235         }, 5000);
236     });
237     $('#di-open').on('click', function () {
238         TB.open("http://www.baidu.com", "_blank", { s: "tidebuy" });
239     });
240     $('#di-api').on('click', function () {
241         TB.api("/Home/Api", { s: "tidebuy" }, function (r) {
242 
243             TB.alert("这个回调可以刷新数据");
244         });
245     });
246     $('#di-task').on('click', function () {
247 
248         //TB.task更多参数见\Content\TB\TB.Task.readme
249         TB.task({
250             args: ["a", "b", "c", 'd', 'e', 'f'],
251             onRun: function (data, index) {
252                 return $.ajax({
253                     url: index == 1 ? "http://a.com" : "/home/Search?keyword=" + data + "&callback=?"
254                 });
255             },
256             onSuccess: function (state) { console.log("成功:" + state.success + "个!"); },
257             onError: function (state) { console.log("失败:" + state.error + "个!"); },
258             onComplete: function (state) { console.log("完成,成功:" + state.success + "个,失败:" + state.error + "个!"); },
259             onProgress: function (state) { console.log("进度:" + state.progress + "/" + state.total); },
260             interval: 1000,
261             dialog: {
262                 formatter: function (state) {
263                     return state.progress + ". 执行任务" + state.index + " [搜索“" + state.arg + "”]:" + (state.data ? state.data.Message : "失败!");
264                 }
265             }
266         }).run();
267     });
268 
269 
270     //在其他框架中可以加入改代码
271     document.addEventListener("PMS_PRODUCT_CHANGE", function (e) {
272         alert(location.href + ' 收到消息(' + e.type + ')...');//弹出的消息里注意看URL的值
273     });
274     $('#di-notity').on('click', function () {
275         //TB.Notity更多参数见\Content\TB\TB.Notity.min.js
276 
277         TB.tabShow("消息测试页", "/home/NotityContent");
278 
279         setTimeout(function () {
280             TB.notity({
281                 event: 'PMS_PRODUCT_CHANGE',
282                 target: 'all',
283                 data: { SPUID: 1 }
284             });
285         }, 2000);
286     });
287 
288     var cache = {
289         scanbox: null
290     };
291 
292     cache.scanbox = TB.scanbox({
293         selecter: "#input",
294         onLoadSuccess: function (json, args) {
295             if (!!json) {
296                 switch (json.type) {
297                     case TB.NUMBER_RULE_PREFIX.包裹编号:
298                     {
299 
300                         $('.media').media({ width: 0, height: 0, src: "/Media/success.wav" });
301                         TB.show(json.Message);
302                         return;
303                     }
304                         break;
305                     case TB.NUMBER_RULE_PREFIX.原包裹编号:
306                     {
307 
308                         $('.media').media({ width: 0, height: 0, src: "/Media/success.wav" });
309                         TB.show(json.Message);
310                         return;
311                     }
312                         break;
313                 }
314                 cache.view.datagrid('load');
315 
316             } else {
317                 cache.scanbox.error("获取数据失败!");
318                 $('.media').media({ width: 0, height: 0, src: "/Media/error.wav" });
319             }
320         },
321         url: "/Logistics/ClientDelivery/InNumberClientDeliveryHandler",
322         onLoadError: function () { },
323         onLoadBefore: function (setting, no) {
324             setting.data = { inNumber: no, packageID: cache.packageId };
325         },
326         onLoadError: function (setting, no) {
327             $('.media').media({ width: 0, height: 0, src: "/Media/error.wav" });
328         }
329 
330     });
331 </script>
332 </th:block>
333 </body>
334 </html>
Welcome.html
复制代码

 

posted @   —八戒—  阅读(1100)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示