本文将采用最新的Solon 3.4.2 版本(截至2025年8月),通过一个完整的渐进式项目示例,跟我一起从零开始构建基于Solon框架的JavaWeb应用。我们将从基础项目搭建开始,逐步添加Web模块、数据访问层、freemarker动态模板等核心功能,最终形成一个功能完整的现代化应用,将粗略展示Solon框架在实际开发中的入门实践。
环境准备与项目初始化
在开始Solon项目开发前,我们需要完成开发环境的准备和基础项目的创建。Solon 3.4.2 支持Java 8至Java 24的所有版本,推荐使用Java 17 LTS以获得最佳性能和特性支持。
环境要求
JDK 17+
Maven 3.9+
IDE(推荐IntelliJ IDEA 2025或VS Code with Java Pack)
创建demo项目
使用官网下的项目生成器勾选最小依赖组合点击生成按钮下载项目,然后通过IDEA导入,我选的是带jetty的Solon Web Servlet
查看pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 继承自Solon框架的父POM,简化了子项目的依赖和插件管理,避免了重复配置 -->
<parent>
<groupId>org.noear</groupId>
<artifactId>solon-parent</artifactId>
<version>3.4.2</version>
<relativePath />
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<description>Demo project for Solon</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!--
Solon框架的核心库,提供IoC容器、AOP支持、基础工具类等核心功能,是其他模块的基础;
solon-lib(基础功能库)是个快捷组合包,自己没有代码,而是组合最基础的日常插件。
-->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-lib</artifactId>
</dependency>
<!-- 集成Jetty嵌入式Web服务器,无需额外配置即可运行Web应用,适合快速开发和部署 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-boot-jetty</artifactId>
</dependency>
<!-- Solon的JSON序列化/反序列化插件,基于Snack3实现,用于处理HTTP请求和响应的JSON数据转换 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-serialization-snack3</artifactId>
</dependency>
<!-- 静态资源处理模块,支持自动映射/static目录下的静态文件(如HTML、CSS、JS) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web-staticfiles</artifactId>
</dependency>
<!-- 跨域资源共享(CORS)支持模块,简化前后端分离开发中的跨域配置 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-web-cors</artifactId>
</dependency>
<!-- 提供参数校验和安全验证功能,如注解驱动的字段校验(类似Spring Validation) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-security-validation</artifactId>
</dependency>
<!-- 集成FreeMarker模板引擎,用于服务端渲染动态页面(如HTML模板) -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-view-freemarker</artifactId>
</dependency>
<!-- logback日志框架 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-logging-logback</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Solon的测试支持模块 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.noear</groupId>
<artifactId>solon-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>tencent</id>
<url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
打开主启动类App.java
,熟练SpringBoot的开发想必已经对这种模板似的代码不陌生了,这里就不解释了
import org.noear.solon.Solon;
import org.noear.solon.annotation.SolonMain;
@SolonMain
public class App {
public static void main(String[] args) {
Solon.start(App.class, args);
}
}
打开默认的接口类DemoController.java:
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
@Controller
public class DemoController {
@Mapping("/hello")
public String hello(@Param(defaultValue = "world") String name) {
return String.format("Hello %s!", name);
}
}
验证项目结构:
运行主类后,控制台应显示类似以下日志,表明Solon已成功启动,接着访问http://localhost:8080/hello能正常返回结果:
App: Start loading
App: Plugin starting
Render mapping: @json=StringSerializerRender#snack3-json
Render mapping: @type_json=StringSerializerRender#snack3-json
View: load: FreemarkerRender
View: load: org.noear.solon.view.freemarker.FreemarkerRender
Render mapping: .ftl=FreemarkerRender
App: Bean scanning
Logging initialized @1082ms to org.eclipse.jetty.util.log.Slf4jLog
jetty-9.4.57.v20241219; built: 2025-01-08T21:24:30.412Z; git: df524e6b29271c2e09ba9aea83c18dc9db464a31; jvm 17.0.15+6-LTS
DefaultSessionIdManager workerName=node0
No SessionScavenger set, using defaults
node0 Scavenging every 600000ms
Started o.e.j.s.ServletContextHandler@4d518b32{/,null,AVAILABLE}
Started ServerConnector@1169afe1{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
Started @1353ms
Connector:main: jetty: Started ServerConnector@{HTTP/1.1,[http/1.1]}{http://localhost:8080}
Server:main: jetty: Started (jetty 9.4/3.4.1) @284ms
App: End loading elapsed=1142ms pid=2868 v=3.4.1
项目初始结构:
solon-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── demo/
│ │ │ └── App.java # 主类
│ │ └── resources/
│ │ ├── app.yml # 主配置文件
│ └── test/
│ └── java/
│ └── features/
│ └── HelloTest.java # 测试代码
├── target/
└── pom.xml
基础配置:
在app.yml
中添加基本配置:
server.port: 8080
solon.app:
name: 'demo-app'
group: 'demo'
solon.logging:
appender:
console:
level: INFO
file:
level: INFO
至此,我们已经完成了一个最基本的Solon Web项目搭建,接下来将逐步添加各功能模块。
REST API开发
上一步我们已经为项目添加Web支持,构建符合现代开发实践的RESTful API。Solon的Web模块设计简洁而强大,支持同步和异步处理模式。
新增第一个Controller:
在上面的DemoController.java
新增json请求方法:
@Get
@Mapping("/json")
public Map<String, Object> jsonExample() {
return Map.of(
"timestamp", System.currentTimeMillis(),
"message", "This is a JSON response",
"data", List.of(1, 2, 3)
);
}
验证API:
启动应用后,访问以下端点:
http://localhost:8080/json
→ 返回JSON响应
增强配置:
在app.yml
中添加Web相关配置:
server:
port: 8080
contextPath: "/api"
# 连接器配置
connector:
maxHttpPostSize: 2MB # 最大POST大小
idleTimeout: 30s # 空闲超时
requestTimeout: 10s # 请求超时
# 响应压缩
compression:
enable: true
mime-types: "text/html,text/plain,text/xml,text/css,text/javascript,application/javascript,application/json"
min-size: 512
# CORS配置
cors:
enable: true
allowed-origins: "*"
allowed-methods: "GET,POST,PUT,DELETE,OPTIONS"
allowed-headers: "Content-Type,Authorization"
max-age: 3600
数据访问层集成
现代应用离不开数据持久化,现在来试试如何在Solon中集成MyBatis-Plus作为ORM框架,并实现事务管理、缓存等企业级特性。
添加数据访问依赖
修改pom.xml:
<dependencies>
<!-- 数据访问核心 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-data</artifactId>
</dependency>
<!-- MyBatis-Plus集成 -->
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-data-mybatis-plus</artifactId>
</dependency>
<!-- 数据库驱动 (以Mysql为例) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.2.0</version>
<scope>runtime</scope>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
</dependencies>
数据库配置
在app.yml
中添加:
solon:
dataSources:
db1:
class: "com.zaxxer.hikari.HikariDataSource"
jdbcUrl: "jdbc:mysql://127.0.0.1:3366/demo?useUnicode=true&characterEncoding=utf-8"
driverClassName: "com.mysql.cj.jdbc.Driver"
username: root
password: root
# db2: 可设置多个数据源
mybatis:
db1:
typeAliases: #支持包名 或 类名 //支持 ** 和 *
- "com.cxl.entity"
mappers: #支持包名 或 类名 或 xml(.xml结尾)//支持 ** 和 *
- "com.cxl.mapper"
- "classpath:mapper/*.xml"
# db2: 对应数据源配置
初始化数据库,这里就沿用之前Micronaut文章中的数据表Person吧。
创建实体类
Person.java
:
package com.cxl.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("person")
public class Person {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String name;
private String birth;
private String status;
}
创建Mapper接口
PersonMapper.java
:
package com.cxl.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cxl.entity.Person;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PersonMapper extends BaseMapper<Person> {
}
创建Service层
IPersonService.java
接口与实现类PersonService.java
:
package com.cxl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cxl.entity.Person;
public interface IPersonService extends IService<Person> {
}
package com.cxl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cxl.entity.Person;
import com.cxl.mapper.PersonMapper;
import com.cxl.service.IPersonService;
import org.noear.solon.annotation.Component;
@Component
public class PersonService extends ServiceImpl<PersonMapper, Person> implements IPersonService {
}
创建Controller
PersonApi.java
:
package com.cxl.api;
import com.cxl.entity.Person;
import com.cxl.service.IPersonService;
import org.noear.solon.annotation.*;
import java.util.List;
@Controller
@Mapping("/person")
public class PersonApi {
@Inject
private IPersonService personService;
@Get
@Mapping
public List<Person> list() {
return personService.list();
}
@Get
@Mapping("/{id}")
public Person getById(@Param long id) {
return personService.getById(id);
}
@Post
@Mapping
public long save(@Body Person person) {
personService.saveOrUpdate(person);
return person.getId();
}
}
验证数据访问
启动应用,检查数据库初始化日志
测试API端点:
GET /person/1
→ 获取ID为1的用户POST /person
→ 创建新用户GET /person
→ 获取用户列表
注意
可能出现的异常:
Missing mapper registration, please check the mappers configuration. 需检查配置文件中是否缺少mybatis下db的mappers选项
org.noear.solon.core.exception.InjectionException: Field injection failed: 'baseMapper'. 注入失败,检查数据源配置,可参考上面配置
数据缓存支持
添加依赖:上一步已经添加了 solon-data 依赖,其中已经包含对应缓存注解,这里直接使用本地内存,也无须添加其它类似redis依赖,如 solon-cache-jedis
配置缓存类型:
# app.yml 文件 demo.cache1: driverType: "local" # 同时打开mybatis日志输出sql,用来验证是否使用了缓存 mybatis: db1: configuration: logImpl: org.apache.ibatis.logging.stdout.StdOutImpl
配置缓存类
Demo1Config.java
:@Configuration public class Demo1Config { @Bean public CacheService cahce1(@Inject("${demo.cache1}") CacheServiceSupplier supplier) { return supplier.get(); } }
在controller中使用@Cache缓存:
@Get @Cache @Mapping public List<Person> list() { return personService.list(); }
访问接口验证 localhost:8080/person,第一次访问控制台会打印出完整sql,后面再访问则不会打印,说明已经缓存成功
动态模板
我们一开始创建项目时就引入了 solon-view-freemarker 模板引擎依赖,现在我们便从Person类着手创建对应的列表视图吧!
solon项目约定了 resources/templates 目录为视图模板文件根目录、resources/static目录为静态文件根目录,我们首先在templates目录(没有则手动创建)下新建一个person.ftl文件:
<#-- person-list.ftl -->
<!DOCTYPE html>
<html>
<head>
<title>人员列表</title>
<meta charset="UTF-8">
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h1>人员列表</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>出生日期</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<#list personList as person>
<tr>
<td>${person.id!}</td>
<td>${person.name!}</td>
<td>${person.birth!}</td>
<td>${person.status!}</td>
</tr>
</#list>
</tbody>
</table>
</body>
</html>
如果不懂freemarker模板语法的话可以查看相关文档,我这里是直接通过通义灵码AI生成的
接着创建Controller请求数据后渲染模板: PersonController.java
@Controller
@Mapping("view")
public class PersonController {
@Inject
private IPersonService personService;
@Mapping("person")
public Object personView(){
ModelAndView vm = new ModelAndView("person.ftl"); //注意,带后缀
vm.put("personList",personService.list());
return vm;
}
}
最终效果:
通过这个小小的实践项目,我们粗略地体验了Solon框架的开发流程和核心功能。整个项目一步步操作下来,个人感觉上手还是挺容易的,主要还是因为文档比较全,而且还有相应的示例代码,是真正的Open,是我在国产框架里看到最有希望的一款了。Solon以其独特的轻量级设计和强大的扩展能力,为Java应用开发提供了全新的选择,特别适合追求性能和开发效率的现代应用场景。无论是初创项目还是企业级应用,Solon都值得考虑作为基础框架。