首页 / 资讯中心 / 文章详情

Java WebApi小程序后台模板:快速开发与JWT鉴权实战

Java WebApi小程序后台模板:快速开发与JWT鉴权实战 ★ FEATURED ARTICLE
简介这份资源是一套基于Java的WebApi小程序后台快速开发模板面向需要快速搭建稳定后台服务的后端开发者与小程序项目团队尤其适合希望缩短开发周期、降低重复编码成本的中级Java工程师。压缩包共708个文件约6.2MB以169个java源码、199个js脚本、74个css样式、45个xml配置、33个jsp页面及23个properties配置为主另含png、gif等图片资源与sql脚本覆盖前后端与数据库各层。模板预置了项目框架、实体类、DAO与Service抽象并定义了登录、查询、增删改查等通用API接口同时融入OAuth2、JWT、CSRF与SQL注入防护等安全实践还提供持续集成部署流程与开发文档示例代码。目前已有33人学习下载读者可据此快速启动项目、按业务扩展接口并参考目录结构理解分层设计与安全配置提升后台服务的可维护性与可扩展性。1. 拿到这套 Java WebApi 小程序后台模板先别急着改包名上周帮一个做社区团购的朋友看后端他团队三个人花了两周从零搭小程序后台登录鉴权、CRUD、分页、统一返回体全在重复造轮子上线前还因为 JWT 过期时间写死在前端被安全扫描打回来。这类场景其实有一套现成的解法基于 Java 的 WebApi 小程序后台快速开发模板。它把项目骨架、分层结构、通用接口、安全组件、部署脚本一次性铺好你拿到手要做的不是从零写而是按业务往里填。这套模板适合两类人一类是接私活或做小团队 MVP 的后端想两三天跑通「小程序登录 → 拿 token → 调业务接口」的闭环另一类是 Java 基础还行但没完整搭过 WebApi 工程的开发者想借一套能跑的结构理解分层和鉴权怎么落地。下面按「它是什么 → 怎么跑起来 → 怎么改 → 坑在哪」的顺序拆代码和参数都能直接抄。2. 模板的工程结构与分层先看懂再动手2.1 目录骨架与各层职责一套合格的 Java WebApi 模板目录结构基本是固定的看懂它比看懂某个类更重要。常见做法是 Maven 多模块或单模块分包核心分层是 controller / service / mapper / entity / config / common。controller 只做参数校验和调用不写业务service 承载业务逻辑和事务mapper 对应 MyBatis 或 MyBatis-Plus 的数据访问entity 是数据库映射对象config 放安全、跨域、序列化配置common 放统一返回体、异常、常量。src/main/java/com/example/template/ ├── controller/ # 接口层只做入参校验和转发 │ ├── AuthController.java # 登录、刷新 token │ └── UserController.java # 用户 CRUD ├── service/ │ ├── AuthService.java │ └── impl/UserServiceImpl.java ├── mapper/ # MyBatis-Plus BaseMapper 继承 │ └── UserMapper.java ├── entity/ │ └── User.java ├── config/ │ ├── SecurityConfig.java # 放行路径、过滤器链 │ └── CorsConfig.java └── common/ ├── Result.java # 统一返回体 └── GlobalExceptionHandler.java这个结构的意义在于小程序端只认接口路径和返回格式后端内部怎么分层它不关心。所以模板把「对外契约」和「对内实现」分开你改业务只动 service 和 mappercontroller 签名尽量别动否则小程序端要跟着改。我一般会先跑一遍mvn dependency:tree看依赖有没有冲突尤其是 Spring Boot 版本和 MyBatis-Plus 版本对不上时启动会直接报NoSuchMethodError这是最常见的翻车点。2.2 统一返回体与全局异常小程序端最在意的契约小程序端解析响应比网页端更脆弱因为它没有浏览器那套容错返回体格式一变就白屏。模板里Result类通常长这样// common/Result.java public class ResultT { private Integer code; // 200 成功401 未登录500 业务异常 private String message; // 给前端提示的文案 private T data; // 业务数据可为 null public static T ResultT ok(T data) { ResultT r new Result(); r.code 200; r.message success; r.data data; return r; } public static T ResultT fail(Integer code, String message) { ResultT r new Result(); r.code code; r.message message; return r; } }参数说明code不要直接用 HTTP 状态码混用业务码和 HTTP 码分开小程序端只判断code 200。message是给人看的别把堆栈塞进去。配合RestControllerAdvice做全局异常捕获任何未处理异常都转成Result.fail(500, 服务繁忙)避免小程序端拿到一坨 HTML 错误页。这一步做完小程序端的请求封装才能稳定否则每个接口都要单独判空。3. 跑通登录闭环JWT 鉴权与小程序 code 换 openid3.1 小程序登录流程与后端接口设计微信小程序登录不是账号密码而是wx.login()拿临时 code后端拿 code 去换 openid 和 session_key。模板里AuthController一般预置了/api/auth/login接口。流程是小程序端调wx.login拿 code → POST 给后端 → 后端用 appid secret code 请求微信接口 → 拿到 openid → 查库或注册用户 → 签发 JWT 返回。// controller/AuthController.java PostMapping(/api/auth/login) public ResultLoginVO login(RequestBody Valid LoginDTO dto) { // dto.code 是小程序 wx.login 拿到的临时凭证 String openid wxService.code2Openid(dto.getCode()); User user userService.findOrCreateByOpenid(openid); String token jwtUtil.generate(user.getId()); LoginVO vo new LoginVO(); vo.setToken(token); vo.setUserId(user.getId()); return Result.ok(vo); }逻辑说明code2Openid里用RestTemplate或HttpClient请求微信的jscode2session接口注意这个接口的 appid 和 secret 必须放配置文件不能硬编码。generate签发 token 时把 userId 放 payload过期时间建议 7 天配合 refresh token 做续期。参数上LoginDTO只暴露 code 字段别把 openid 暴露给前端传否则等于把身份伪造的口子留出来。3.2 JWT 过滤器与放行路径配置签发完 token下一步是校验。模板里通常有一个JwtAuthenticationFilter继承OncePerRequestFilter在SecurityConfig里注册。核心逻辑是从Authorization头取Bearer xxx解析 payload 拿 userId塞进SecurityContext。// config/SecurityConfig.java Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .antMatchers(/api/auth/login, /api/auth/refresh).permitAll() .anyRequest().authenticated() .and() .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); }参数说明permitAll的路径必须精确登录和刷新 token 放行其他一律拦截。csrf().disable()是因为小程序端不走 Cookie用 token 鉴权CSRF 防护在这里没有意义但如果你同时提供网页后台就要单独给网页端开 CSRF。常见坑是放行路径写成/api/auth/**把刷新接口也放开了结果 refresh token 被滥用。我一般会显式列出放行路径不用通配符。4. 数据层与 CRUDMyBatis-Plus 怎么配才不返工4.1 实体映射与自动建表模板里 entity 用 MyBatis-Plus 注解映射表结构TableName、TableId、TableField三个注解覆盖大部分场景。热搜里常有人问「MyBatis-Plus 根据 Java 实体类生成创建表的 SQL」其实模板里一般会带一个schema.sql或 Flyway 迁移脚本而不是运行时自动建表因为生产环境自动建表是危险操作。// entity/User.java Data TableName(t_user) public class User { TableId(type IdType.AUTO) private Long id; TableField(openid) private String openid; TableField(nickname) private String nickname; TableField(create_time) private LocalDateTime createTime; }逻辑说明IdType.AUTO对应数据库自增如果用小程序的分布式场景建议换ASSIGN_ID雪花算法。TableField显式写列名避免驼峰转下划线的全局配置被改后映射错位。建表 SQL 放resources/db/migration/V1__init.sql用 Flyway 管理版本每次改表加一个 V2、V3别直接改 V1否则已部署环境对不上。4.2 分页与条件查询的通用写法小程序列表页几乎都要分页模板里一般封装了PageResult和 MyBatis-Plus 的Page对象。// service/impl/UserServiceImpl.java public PageResultUserVO pageUsers(int pageNum, int pageSize, String keyword) { PageUser page new Page(pageNum, pageSize); LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { wrapper.like(User::getNickname, keyword); } wrapper.orderByDesc(User::getCreateTime); userMapper.selectPage(page, wrapper); // 转 VO别把 entity 直接返回给前端 ListUserVO list page.getRecords().stream() .map(this::toVO).collect(Collectors.toList()); return new PageResult(list, page.getTotal(), pageNum, pageSize); }参数说明pageNum从 1 开始pageSize建议后端限制上限 100防止小程序端传 10000 把库拖垮。LambdaQueryWrapper比字符串拼接安全避免 SQL 注入。返回时转 VO 是关键entity 里的 openid、内部状态字段不该给前端。常见坑是直接返回PageUser把 MyBatis-Plus 的分页结构暴露出去小程序端解析要多一层而且字段全泄露。5. 避坑与排查这几处翻车我见过太多次5.1 启动报 NoSuchMethodError 或 Bean 冲突现象mvn spring-boot:run直接抛NoSuchMethodError或BeanDefinitionOverrideException。原因Spring Boot 版本和 MyBatis-Plus、JWT 库版本不匹配或者两个依赖都引入了不同版本的spring-core。解决先mvn dependency:tree | grep spring-core看有没有重复用exclusions排掉旧版本MyBatis-Plus 用mybatis-plus-boot-starter而不是单独引mybatis版本对齐 Spring Boot 官方兼容表。5.2 小程序端一直 401但 Postman 能通现象Postman 带 token 请求正常小程序真机一直 401。原因小程序端请求头字段名大小写或Bearer前缀没带或者 token 存了但请求时没读出来。解决在小程序request封装里统一加header: { Authorization: Bearer token }并在后端过滤器里打印一次请求头确认。另外检查 token 是否过期真机时间不准会导致 JWT 校验失败这是玄学但真实存在。5.3 跨域配置在真机失效现象开发者工具里正常真机请求报跨域。原因小程序真机不走浏览器同源策略但如果你同时提供 H5 后台CorsConfig里allowedOrigins写了*又开了allowCredentials浏览器会拒绝。解决allowedOrigins显式写域名allowCredentials(true)时不能用*。小程序端本身不需要 CORS别把两套配置混在一起。5.4 数据库连接池耗尽现象压测或上线后偶发Connection is not available。原因HikariCP 默认最大连接 10小程序并发一上来就排队。解决spring.datasource.hikari.maximum-pool-size调到 2050同时检查 service 里有没有手动getConnection没关闭的代码。模板里一般用Transactional管理别在循环里开事务。5.5 统一返回体被序列化两次现象小程序端拿到的 data 是字符串而不是对象。原因controller 返回Result又被某个ResponseBodyAdvice包了一层或者用了 FastJSON 和 Jackson 混用。解决只保留一套序列化方案模板默认 Jackson 就别引 FastJSON检查有没有自定义HttpMessageConverter重复注册。6. 进阶把模板改造成可复用的多环境部署骨架模板跑通只是第一步真正省时间的是把它改成多环境可切换的骨架。我一般会做三件事。第一用application-dev.yml、application-test.yml、application-prod.yml分离配置spring.profiles.active通过启动参数注入别把数据库密码写死在代码里。第二把微信 appid、secret、JWT 密钥放环境变量或配置中心模板里用${WX_APPID}占位本地用.env或 IDE 环境变量补。第三加一个Dockerfile和docker-compose.yml把 MySQL 和 Redis 一起编排新同事 clone 下来docker-compose up就能跑不用配环境配半天。# application-prod.yml spring: datasource: url: jdbc:mysql://${DB_HOST}:3306/template?useSSLfalse username: ${DB_USER} password: ${DB_PASSWORD} hikari: maximum-pool-size: 30 wx: appid: ${WX_APPID} secret: ${WX_SECRET} jwt: secret: ${JWT_SECRET} expire: 604800 # 7 天单位秒验证方法本地用devprofile 跑通登录再用prodprofile 加环境变量启动确认没有硬编码残留。可以用grep -rn password\|secret src/main/resources扫一遍凡是明文出现的都要改。另外建议加一个/api/health接口返回应用状态和数据库连通性部署后先打这个接口比直接打登录接口更快定位是应用没起来还是数据库没连上。从那以后我每次拿到一套新模板都强制先跑一遍「登录 → 带 token 查列表 → 改一条数据 → 再查」的闭环再动任何业务代码。这套动作能暴露 80% 的配置问题比读文档快得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站