网站首页 > 开源技术 正文
七、模板引擎
1.简介
目前Java Web开发推荐使用模板引擎,不建议使用jsp页面
- jsp的缺点:本质时Servlet,需要后台进行编译,效率较低
- 模板引擎:不需要编译,速度快
常用的模板引擎:Freemarker、Thymeleaf等
SpringBoot推荐Thymeleaf,且默认不支持jsp,因为jsp必须要打成war包。
补充:目前主流的web开发更推荐前后端分离,前端使用MVVM框架,Vue.js、Angular、React等
2.Thymeleaf的使用
步骤:
1.添加Thymeleaf的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
2.将html页面放到templates下
templates下的html不能直接访问,需要使用Controller跳转,由Thymeleaf进行渲染
ThymeleafAutoConfiguration—>ThymeleafProperties
public static final String DEFAULT_PREFIX = "classpath:/templates/";public static final String DEFAULT_SUFFIX = ".html";
默认拼接前缀和后缀
? 3.使用thymeleaf
<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h2>success</h2> <!--使用th:text属性设置元素中的文本,表达式:${}可以获取作用域中的数据--> <p th:text="${name}"></p></body></html>
? 4.修改页面后,让其实时生效
? 由于thymeleaf默认启用了缓存,将缓存禁用掉
#禁用thymeleaf的缓存spring.thymeleaf.cache=false
? 补充:还需要开启idea的自动编译,idea默认保存时不会自动编译
3.语法规则
3.1 常用属性
- th:text、th:utext
- 设置元素中的文本内容
- th:text对特殊字符进行转义,等价于内联方式[[${ }]]
- th:utext不对特殊字符集进行转义,等价于内联方式[(${ })]
<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <!--th:text、th:utext--> <div th:text="${hello}">aaa</div> <div th:utext="${hello}">bbb</div> <!--使用内联方式,可以在文本前后添加内容--> <div>[[${hello}]]aaa</div> <div>[(${hello})]bbb</div></body></html>
- th:html原生属性
- 用来替换指定的html原生属性的值
@RequestMapping("/test2")public String test2(Model model){ model.addAttribute("hello", "<mark>你好</mark>"); model.addAttribute("id", "mydiv"); model.addAttribute("title", "this is a div"); return "result";}<!--th:html原生属性--><div id="div1" title="这是一个div" th:id="${id}" th:title="${title}">div</div>
- th:if、th:unless、th:switch、th:case
- 条件判断,类似于if
<!--th:if、th:unless、th:switch、th:case--><div th:if="${age>=18}">成年</div><p th:unless="${age<18}">成年</p><p th:switch="${role}"> <span th:case="student">学生</span> <span th:case="teacher">老师</span> <span th:case="*">其他</span></p><hr>
- th:each
- 循环,类似于for each
<!--th:each--><ul> <li th:each="name:${names}" th:text="${name}"></li></ul>
- th:object、th:field
- 用于表单数据对象的绑定,将表单绑定到Controller的一个JavaBean参数,常与th:field
- 一起使用,需要和*{}选择表达式配合使用
<!--th:object、th:field--><h2>修改用户信息</h2><!--th:object指定对象,th:field指定属性--><form action="modify" method="post" th:object="${user}"> 编号:<input type="text" th:field="*{id}" readonly> <br> 姓名:<input type="text" th:field="*{name}"> <br> 年龄:<input type="text" th:field="*{age}"> <br> <input type="submit" value="修改"></form>
- th:fragment
- 声明代码片段,常用于页面头部和尾部的引入
<!--th:fragment--><header th:fragment="head"> 这是页面的头部,导航</header>
- th:include、th:insert、th:replace
- 引入代码片段,类似于jsp:include
<!--th:include、th:insert、th:replace--><!--引入templates/include下的header.html页面中的fragment为head的片段--><div th:include="include/header::head"></div>
- 三者之间的区别
th:include会保留自己的标签,不要th:fragment的标签(Thymeleaf 3.0 后不推荐使用)
th:insert保留自己的标签,也保留th:fragment的标签
th:relpace不保留自己的标签,保留thfragment的标签
3.2 表达式
- ${} 变量表达式
- 获取对象的属性、方法
<!DOCTYPE html><html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <!--获取对象的属性、方法--> <div th:text="${user.name}"></div> <div th:text="${user['age']}"></div> <div th:text="${users[1].name}"></div> <!--<div th:text="${users.size()}"></div>--> <div>[[${users.size()}]]个</div></body></html>
- 使用内置的基本对象,如session和application
<!--使用内置基本对象--><div th:text="${session.sex}"></div><div th:text="${application.hobby}"></div>
- 使用内置的工具对象,如#strings、#dates、#arrays、#lists、#maps等
<!--使用内置的工具对象--><div th:text="${#strings.startsWith(user.name, 't')}"></div><div th:text="${#strings.substring(user.name, 0, 2)}"></div><div th:text="${#strings.length(user.name)}"></div><div th:text="${#dates.createNow()}"></div><div th:text="${#dates.create(2018, 10, 14)}"></div><div th:text="${#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}"></div>
- *{} 选择表达式(星号表达式)
<!--*{}选择表达式--><div th:object="${user}"> <div th:text="*{id}"></div> <div th:text="*{name}"></div> <div th:text="*{age}"></div></div>
- @{} url表达式
<head> <meta charset="UTF-8"> <title>Title</title> <!--url表达式引入css文件--> <link rel="stylesheet" th:href="@{/css/style.css}"></head><!--url表达式--><a th:href="@{/findUser(name=${user.name})}">查询指定的用户信息</a><a href="product/list.html" th:href="@{/product/list}">商品列表</a><script th:src="@{/js/common.js}"></script>
- 运算符
- eq gt le == != 三目运算符
4.热部署
使用SpringBoot提供的devtools实现热部署
原理:实时监控classpath下文件的变化,如果发生变化自动重启
配置:添加devtools依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <!--该依赖不传递--> <optional>true</optional></dependency>
八、扩展默认的SpringMVC功能
1.简介
? 以前在SpringMVC中可以通过如下代码进行视图跳转和拦截器:
<mvc:view-controller path="/showLogin" view-name="login"/><mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean class="com.luyi.interceptor.HelloInterceptor"/> </mvc:interceptor></mvc:interceptors>
SpringBoot默认配置默认没有提供以上功能,需要自己扩展,使用WebMvcConfigurer接口
2.基本操作
? 步骤:
? 1.定义一个配置类,实现WebMvcConfigurer接口
? 2.实现需要的方法
/** * Author: LuYi * Date: 2019/10/29 17:58 * Description: 扩展默认的SpringMVC的功能 * 要求: * 1.将该类标记为配置类 * 2.实现WebMvcConfigurer接口 * 3.根据需要实现接口中相应的方法 * * 注意:这个接口中的方法都添加了jdk1.8中的default方法修饰,不强制实现所有方法(jdk1.8新特性) * 在SpringBoot1.0中是继承WebMvcConfigurerAdapter类,SpringBoot2.0是基于jdk1.8的, * 所以通过实现WebMvcConfigurer的方式 *///将该类设置为配置类@Configurationpublic class CustomMvcConfig implements WebMvcConfigurer { //添加ViewController @Override public void addViewControllers(ViewControllerRegistry registry) { //将访问login页面的url设置为showLogin registry.addViewController("/showLogin").setViewName("login"); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") .excludePathPatterns("/test2"); }}
九、全局异常处理
1.简介
? 当程序出现异常时进行全局处理,SpringBoot默认的异常信息提示:Whitelabel Error Page
两种方式:
- 定义错误码页面
- 定义异常通知
2.定义错误码页面
? 创建 错误状态码.html页面,放到templates/error目录中,当发生错误时会自动到该目录下查找对应的错误页面
? 可以创建如 4xx.html或5xx.html页面,用来匹配所有该类型的错误(会优先进行精确匹配
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h2>5xx错误</h2> <h3>状态码:[[${status}]]</h3> <h3>异常消息:[[${message}]]</h3> <h3>错误提示:[[${error}]]</h3> <h3>时间戳:[[${timestamp}]]</h3></body></html>
3.定义异常通知
/** * Author: LuYi * Date: 2019/10/29 18:45 * Description: 异常通知:用来处理全局异常 */@ControllerAdvicepublic class ExceptionAdvice { @ExceptionHandler(ArithmeticException.class) public String arithmetic(Exception e){ System.out.println("警报:程序出现异常,发短信:" + e.getMessage()); return "error/5xx"; } @ExceptionHandler(Exception.class) public String exception(Exception e){ System.out.println("警报:程序出现异常,发邮件:" + e.getMessage()); return "error/5xx"; }}
十、关于Servlet容器
1.简介
? SpringBoot中默认内置了Servlet:Tomcat
? 问题:SpringBoot默认以jar包方式启动内置的Servlet容器,没有web.xml文件,如何注册Servlet三大组件:Servlet、Filter、Listener
? 解决:通过自定义Servlet配置,使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean
2.注册Servlet组件
? 步骤:
? 1.定义一个配置类
? 2.自定义一个方法,用来注册组件
/** * Author: LuYi * Date: 2019/10/29 19:12 * Description: 自定义Servlet配置 *///将该类声明为配置类@Configurationpublic class CustomServletConfig { //将方法返回值放到Spring容器 @Bean public ServletRegistrationBean myServlet(){ ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>(); //对MyServlet进行注册 registrationBean.setServlet(new MyServlet()); ArrayList<String> urls = new ArrayList<>(); urls.add("/myServlet"); registrationBean.setUrlMappings(urls); return registrationBean; } //注册Filter @Bean public FilterRegistrationBean myFilter(){ FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(); //注册filter registrationBean.setFilter(new MyFilter()); registrationBean.addUrlPatterns("/showLogin", "/test1"); return registrationBean; } //注册Listener @Bean public ServletListenerRegistrationBean myListener(){ ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(); registrationBean.setListener(new MyListener()); return registrationBean; }}
3.使用外部的Servlet容器
3.1 优缺点
? 使用内置Servlet容器:
? 优点:使用简单,将应用打成jar包
? 缺点:不支持jsp、可定制性不高
? 使用外部的Servlet容器
? 优点:支持jsp、可定制性高
? 缺点:需要将应用打成war包
3.2 操作步骤
? 步骤:
? 1.创建一个Maven的war工程
? 有如下三个变化
? 1.打包方式变为war
<packaging>war</packaging>
? 2.将内置的tomcat的scope配置为provided
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope></dependency>
? 3.定义了一个SpringBootServletInitializer的子类
/** * 要求: * 1.必须继承SpringBootServletInitializer * 2.重写configure()方法 * 3.调用SpringApplicationBuilder的sources()方法,传入主程序类的 */public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Springboot05WarApplication.class); }}
? 2.创建web目录的结构
? 3.配置前缀和后缀
spring.mvc.view.prefix=/WEB-INF/views/spring.mvc.view.suffix=.jsp
? 4.配置Tomcat
? 要使用SpringBoot需要的Tomcat版本
十一、SpringBoot数据访问
1.JDBC
? 步骤:
? 1.创建工程,选择以下模板:web、jdbc、mysql
? 2.配置数据库连接信息
#指定数据库连接参数spring.datasource.driver-class-name= com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=falsespring.datasource.username=rootspring.datasource.password=root#指定数据源spring.datasource.type=org.apache.commons.dbcp.BasicDataSource
? 3.测试
@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTestclass Springboot06JdbcApplicationTests { @Autowired private DataSource dataSource; @Test void contextLoads() throws SQLException { System.out.println("---------------------------"); System.out.println("DataSource的类型: " + dataSource.getClass()); System.out.println("Connection的连接: " + dataSource.getConnection()); }}
? 4.配置连接池参数
spring.datasource.initialSize=10spring.datasource.maxActive=100spring.datasource.minIdle=5spring.datasource.maxWait=50000
? 问题:添加上面的参数不生效,因为SpringBoot默认并不支持这些参数(DataSourceProperties)
? 解决:自定义数据源配置
/** * Author: LuYi * Date: 2019/10/30 16:09 * Description: 描述 */@Configurationpublic class DatasourceConfig { @Bean //从配置文件中读取spring.datasource属性,并注入给数据源的属性 @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(){ return new BasicDataSource(); }}
? 5.使用JdbcTemplate操作数据库
/** * Author: LuYi * Date: 2019/10/30 16:17 * Description: 描述 */@Controller@RequestMapping("/user")public class UserController { @Autowired private JdbcTemplate jdbcTemplate; @RequestMapping("/findAll") @ResponseBody public List<Map<String, Object>> findAll(){ String sql = "select * from t_user"; List<Map<String, Object>> list = jdbcTemplate.queryForList(sql); return list; }}
2.MyBatis
2.1 基本步骤
? 1.创建工程,先择以下模块:web、mybatis
? 2.配置数据源
#配置DataSourcespring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root initialSize: 5 maxActive: 100 minIdle: 3 maxWait: 50000#配置MyBatismybatis: type-aliases-package: com.luyi.pojo mapper-locations: classpath:mapper/*.xml
? 3.编写Mapper、Service、Controller
? 4.配置MyBatisConfig配置类
/** * Author: LuYi * Date: 2019/10/30 16:57 * Description: 描述 */@Configuration//扫描MyBatis接口所在的包@MapperScan("com.luyi.mapper")public class MyBatisConfig { @Bean //加载主配置文件,注入配置信息 @ConfigurationProperties(prefix = "spring.datasource") public DruidDataSource druidDataSource(){ return new DruidDataSource(); }}
2.2 配置PageHelper分页插件
? 步骤:
? 1.添加PageHelper依赖
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.10</version></dependency>
? 2.配置PageHelper的属性
#配置PageHelperpagehelper: helper-dialect: mysql
? 3.使用PageHelper
@Overridepublic PageInfo<User> findByPage(int pageNum, int pageSize) { //使用PageHelper设置分页 PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.selectAll(); PageInfo<User> pageInfo = new PageInfo<>(users); return pageInfo;}
2.3 使用MyBatis Plus
? 参考:http://mp.baomidou.com/
? 步骤:
? 1.添加MyBatis Plus的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.20</version></dependency>
? 2.配置全局配置文件
#配置DataSourcespring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root initialSize: 5 maxActive: 100 minIdle: 3 maxWait: 50000#配置MyBatis Plusmybatis-plus: mapper-locations: classpath:mapper/*Mapper.xml type-aliases-package: com.luyi.pojo global-config: db-config: #主键类型 id-type: auto #字段策略 field-strategy: not_empty #驼峰下划线转换 table-underline: true #全局表前缀 table-prefix: t_ #刷新mapper神器 refresh-mapper: true
? 3 配置MyBatis Plus
/** * Author: LuYi * Date: 2019/10/31 9:59 * Description: 描述 */@Configuration@MapperScan("com.luyi.mapper")public class MyBatisPlusConfig { /** * 分页插件,自动识别数据库类型 * @return */ @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } @Bean @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(){ return new DruidDataSource(); }}
? 4.编写Mapper,继承BaseMapper
/** * Author: LuYi * Date: 2019/10/31 10:07 * Description: 继承BaseMapper接口 */public interface UserMapper extends BaseMapper<User> {}
? 5.测试
@RunWith(SpringRunner.class)@SpringBootTestclass Springboot08MpApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { } @Test public void add(){ User user = new User(); user.setUsername("xxx"); user.setPassword("111"); userMapper.insert(user); System.out.println("-------------" + user); } @Test public void removeById(){ int i = userMapper.deleteById(3); System.out.println(i); } @Test public void modifyById(){ User user = new User(); user.setId(6); user.setUsername("zhangsan"); user.setPassword("123"); userMapper.updateById(user); } @Test public void findById(){ User user = userMapper.selectById(1); System.out.println(user); } @Test public void findByCondition(){ //定义条件构造器,用来封装查询条件 QueryWrapper<User> wrapper = new QueryWrapper<>();// wrapper.eq("username", "tom"); wrapper.like("username", "%a%"); List<User> users = userMapper.selectList(wrapper); for (User user : users) { System.out.println(user); } } @Test public void findByPage(){ Page<User> page = new Page<>(2, 2); QueryWrapper<User> wrapper = new QueryWrapper<>(); IPage<User> userIPage = userMapper.selectPage(page, wrapper.select("id", "username", "password")); assertThat(page).isSameAs(userIPage); System.out.println("总条数---->" + userIPage.getTotal()); System.out.println("当前页数---->" + userIPage.getCurrent()); System.out.println("当前每页显示数---->" + userIPage.getSize()); System.out.println(userIPage.getRecords()); System.out.println("----------自带分页----------"); }}
补充:lombok的使用
步骤:
? 1.添加依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> <scope>provided</scope></dependency>
? 2.使用lombok提供的注解
/** * Author: LuYi * Date: 2019/10/30 16:32 * Description: Lombok的使用 * Lombok提供了许多注解,标注在类上或者属性上 */@Getter@Setter@ToString@Data //相当于以上注解@TableName(value = "t_user") //指定当前数据库表的名称public class User implements Serializable { private Integer id; private String username; private String password;}
? 3.在Idea中安装lombok插件
? 由于源代码中没有getter/setter等的定义,Idea无法识别,可以安装lombok插件解决
十二、SpringBoot整合Redis
1.简介
? Redis是一个内存数据库,可以作为缓存、消息中间件、key-value数据库等来使用
2.操作
? 步骤:
? 1.添加依赖
? 注意:在SpringBoot1.0中使用的Redis客户端时Jedis,在SpringBoot2.0中使用的时Lettuce
<!--整合Redis--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <!--SpringBoot2.0使用的Redis客户端时Lettuce--> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId></dependency>
? 2.配置redis
#redis配置spring.redis.host=192.168.52.128spring.redis.port=6379spring.redis.database=0spring.redis.jedis.pool.max-active=100spring.redis.jedis.pool.max-idle=10spring.redis.jedis.pool.min-idle=3
? 3.基本用法
使用SpringDataRedis提供的工具类:StringRedisTemplate、RedisTemplate
? 封装JsonUtils
/** * Author: LuYi * Date: 2019/10/31 17:37 * Description: Json工具类,基于jackson */public class JsonUtils { //获取jackson对象 private static ObjectMapper objectMapper = new ObjectMapper(); /** * 将对象转换为Json字符串 */ public static String objectToJson(Object obj){ try { //将对象转换为Json字符串 String jsonStr = objectMapper.writeValueAsString(obj); return jsonStr; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } /** * 将Json字符串转换为对象 */ public static <T> T jsonToObject(String jsonStr, Class<T> clazz){ try { T t = objectMapper.readValue(jsonStr, clazz); return t; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }}
? 测试
@RunWith(SpringRunner.class)@SpringBootTestpublic class Springboot09RedisApplicationTests { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisTemplate<String, String> redisTemplate; @Test public void contextLoads() { } /** * 使用StringRedisTemplate * Redis数据类型:String、List、Set、ZSet、Hash */ @Test public void test1(){ /** * 操作redis */// ValueOperations<String, String> value = stringRedisTemplate.opsForValue();// ListOperations<String, String> list = stringRedisTemplate.opsForList();// SetOperations<String, String> set = stringRedisTemplate.opsForSet();// ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();// HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash(); /** * 操作String */// stringRedisTemplate.opsForValue().set("username", "admin");// System.out.println(stringRedisTemplate.opsForValue().get("username")); /** * 操作List */// stringRedisTemplate.opsForList().leftPush("name", "tom");// stringRedisTemplate.opsForList().leftPushAll("name", "aaa", "bbb", "ccc");// System.out.println(stringRedisTemplate.opsForList().range("name", 0, -1)); /** * 存储对象 */ User user = new User(); user.setId(1001); user.setUsername("tom"); user.setPassword("123"); //将对象转换为json格式 String jsonStr = JsonUtils.objectToJson(user); System.out.println(jsonStr); stringRedisTemplate.opsForValue().set("user", jsonStr); //获取jsonStr String str = stringRedisTemplate.opsForValue().get("user"); //将str转换为对象 User u = JsonUtils.jsonToObject(str, User.class); System.out.println(u); } /** * 使用redisTemplate */ @Test public void test2(){ redisTemplate.opsForValue().set("sex", "male"); String sex = redisTemplate.opsForValue().get("sex"); System.out.println(sex); }}
需要springboot面试题私信“资料”获取
猜你喜欢
- 2024-09-08 Try catch 太烦人了?只需一步一次搞定 Exception
- 2024-09-08 vue多实体参数怎么传?(vue如何传参)
- 2024-09-08 Mybatis-Plus常用的查询方法——看这一篇就够了!「图文例子」
- 2024-09-08 你这代码写得真丑,满屏的try-catch,全局异常处理不会吗?下
- 2024-09-08 mybatis-plus 团队新作 mybatis-mate 轻松搞定企业级数据处理
- 2024-09-08 「Spring Cloud」新闻头条微服务项目:自媒体文章管理
- 2024-09-08 最快MyBatis-Plus入门使用(mybatis-plus-plus)
- 2024-09-08 再也不用写CURD代码了,Mybatis-plus帮你全搞定
- 2024-09-08 MyBatis-Plus快速入门(一)(mybatis-plus-plus)
- 2024-09-08 Mybatis-Plus 详解(二)(mybatisplus in)
你 发表评论:
欢迎- 07-10公司网站建站选择:人工建站和源码建站分析
- 07-10多用途游戏娱乐新闻网站HTML5模板
- 07-10站长教你搭建属于自己的网站(搭建网站的步骤)
- 07-10php宝塔搭建部署实战响应式塑料封条制品企业网站模板源码
- 07-10自适应响应式汽车配件类网站源码 html5高端大气汽车网站织梦模板
- 07-10网站标签怎么设置?(网站标签怎么设置比较好)
- 07-10PageAdmin企业网站制作中踩过的坑
- 07-10豆包给我输出的html在线象棋源码(有点简单)
- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)