add: jetty的session持久化,当前完成jdbc/file/ioc模式.

提示一下, 这个跟shiro的session持久化不是一个东西,功能类似,但不依赖shiro

使用shiro的话, 建议用shiro的session持久化.
This commit is contained in:
Wendal Chen 2019-06-27 11:41:09 +08:00
parent fb5f0f6cb3
commit 825b37aa06
26 changed files with 849 additions and 0 deletions

View File

@ -0,0 +1,7 @@
FROM azul/zulu-openjdk:8
MAINTAINER wendal <wendal1985@gmail.com>
ENTRYPOINT ["/usr/bin/java", "-jar", "/usr/share/nb.jar"]
# Add the service itself
ARG JAR_FILE
ADD target/${JAR_FILE} /usr/share/nb.jar

View File

@ -0,0 +1,7 @@
server.port=8080
server.host=0.0.0.0
jdbc.url=jdbc:h2:mem:~
nutz.dao.interceptor.time.enable=true
nutz.dao.interceptor.cache.enable=true

View File

@ -0,0 +1,84 @@
<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>
<parent>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-demo-simple</artifactId>
<version>2.1.2</version>
</parent>
<artifactId>nutzboot-demo-simple-dao-multi</artifactId>
<properties>
<docker.image.prefix>nutzboot</docker.image.prefix>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-dao</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/nutz/org.nutz.boot.starter.NbStarter</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>io.nutz.demo.simple.MainLauncher</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,30 @@
package io.nutz.demo.simple;
import org.nutz.boot.NbApp;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import io.nutz.demo.simple.bean.User;
@IocBean(create="init")
public class MainLauncher {
@Inject
protected Dao dao;
public void init() {
dao.create(User.class, true);
dao.insert(new User("apple", 40, "北京"));
dao.insert(new User("ball", 30, "未知"));
dao.insert(new User("cat", 50, "温哥华"));
dao.insert(new User("fox", 51, "纽约"));
dao.insert(new User("bra", 25, "济南"));
dao.insert(new User("lina", 50, "深圳"));
}
public static void main(String[] args) throws Exception {
new NbApp().setPrintProcDoc(true).run();
}
}

View File

@ -0,0 +1,51 @@
package io.nutz.demo.simple.bean;
import org.nutz.dao.entity.annotation.Id;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
@Table("t_user")
public class User {
@Id
private long id;
@Name
private String name;
private int age;
private String location;
public User() {
}
public User(String name, int age, String location) {
super();
this.name = name;
this.age = age;
this.location = location;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}

View File

@ -0,0 +1,45 @@
package io.nutz.demo.simple.module;
import java.util.List;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.pager.Pager;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import io.nutz.demo.simple.bean.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@Api("user")
@At("/user")
@IocBean
public class UserModule {
@Inject
Dao dao;
@ApiOperation(value = "获取用户总数", notes = "获取用户总数", httpMethod="GET", response=Long.class)
@Ok("raw")
@At
public long count() {
return dao.count(User.class);
}
@ApiOperation(value = "查询用户列表", notes = "可分页", httpMethod="GET")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNumber", paramType="query", value = "起始页是1", dataType="int", required = false, defaultValue="1"),
@ApiImplicitParam(name = "pageSize", paramType="query", value = "每页数量", dataType="int", required = false, defaultValue="20"),
})
@Ok("json:full")
@At
public List<User> query(@Param("..")Pager pager) {
return dao.query(User.class, Cnd.orderBy().asc("age"), pager);
}
}

View File

@ -0,0 +1,7 @@
server.port=8080
server.host=0.0.0.0
jdbc.url=jdbc:h2:mem:~
nutz.dao.interceptor.time.enable=true
nutz.dao.interceptor.cache.enable=true

View File

@ -0,0 +1,8 @@
log4j.rootLogger=info,Console
log4j.logger.org.nutz=debug
log4j.logger.org.eclipse.jetty=info
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss.SSS}] %5p [%t] --- %c{1}: %m%n

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello, So NB!</title>
</head>
<body>
<div>
<h2>Hello, So NB!</h2>
</div>
<div>
<h2>
<a href="swagger/index.html">查看api文档(由Swagger生成)</a>
</h2>
</div>
<div>
<h2><a href="druid/">Druid监控页面,用户名密码在日志搜索 "druid stat view"</a></h2>
</div>
</body>
</html>

View File

@ -0,0 +1,12 @@
server.port=8080
server.host=0.0.0.0
jdbc.url=jdbc:h2:mem:~
jdbc.url=jdbc:h2:mem:~
jdbc.url=jdbc:h2:mem:~
jdbc.url=jdbc:h2:mem:~
jdbc.url=jdbc:h2:mem:~
jdbc.url=jdbc:h2:mem:~
nutz.dao.interceptor.time.enable=true
nutz.dao.interceptor.cache.enable=true

View File

@ -0,0 +1,29 @@
package io.nutz.demo.simple;
import javax.sql.DataSource;
import org.nutz.dao.Dao;
import org.nutz.dao.impl.NutDao;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import com.alibaba.druid.pool.DruidDataSource;
@IocBean
public class MyBeans {
@Inject
protected PropertiesProxy conf;
@IocBean
public Dao dao2(@Inject DataSource dataSource2) {
return new NutDao(dataSource2);
}
@IocBean
public DataSource dataSource2(@Inject DataSource dataSource2) {
return conf.make(DruidDataSource.class, "jdbc2.");
}
}

View File

@ -0,0 +1,62 @@
<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/elasticsearch/6.3.2/elasticsearch-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/elasticsearch-core/6.3.2/elasticsearch-core-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/elasticsearch-secure-sm/6.3.2/elasticsearch-secure-sm-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/elasticsearch-x-content/6.3.2/elasticsearch-x-content-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.17/snakeyaml-1.17.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/core/jackson-core/2.8.10/jackson-core-2.8.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.8.10/jackson-dataformat-smile-2.8.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-yaml/2.8.10/jackson-dataformat-yaml-2.8.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.8.10/jackson-dataformat-cbor-2.8.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-core/7.3.1/lucene-core-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-analyzers-common/7.3.1/lucene-analyzers-common-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-backward-codecs/7.3.1/lucene-backward-codecs-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-grouping/7.3.1/lucene-grouping-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-highlighter/7.3.1/lucene-highlighter-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-join/7.3.1/lucene-join-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-memory/7.3.1/lucene-memory-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-misc/7.3.1/lucene-misc-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-queries/7.3.1/lucene-queries-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-queryparser/7.3.1/lucene-queryparser-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-sandbox/7.3.1/lucene-sandbox-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-spatial/7.3.1/lucene-spatial-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-spatial-extras/7.3.1/lucene-spatial-extras-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-spatial3d/7.3.1/lucene-spatial3d-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/lucene/lucene-suggest/7.3.1/lucene-suggest-7.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/elasticsearch-cli/6.3.2/elasticsearch-cli-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/net/sf/jopt-simple/jopt-simple/5.0.2/jopt-simple-5.0.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/carrotsearch/hppc/0.7.1/hppc-0.7.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/joda-time/joda-time/2.9.9/joda-time-2.9.9.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/tdunning/t-digest/3.2/t-digest-3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/hdrhistogram/HdrHistogram/2.1.9/HdrHistogram-2.1.9.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/jna/4.5.1/jna-4.5.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/client/transport/6.3.2/transport-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/transport-netty4-client/6.3.2/transport-netty4-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-buffer/4.1.16.Final/netty-buffer-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-codec/4.1.16.Final/netty-codec-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-codec-http/4.1.16.Final/netty-codec-http-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-common/4.1.16.Final/netty-common-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-handler/4.1.16.Final/netty-handler-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-resolver/4.1.16.Final/netty-resolver-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/io/netty/netty-transport/4.1.16.Final/netty-transport-4.1.16.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/reindex-client/6.3.2/reindex-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/client/elasticsearch-rest-client/6.3.2/elasticsearch-rest-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore/4.4.5/httpcore-4.4.5.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpasyncclient/4.1.2/httpasyncclient-4.1.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/httpcomponents/httpcore-nio/4.4.5/httpcore-nio-4.4.5.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-codec/commons-codec/1.10/commons-codec-1.10.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/lang-mustache-client/6.3.2/lang-mustache-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/github/spullara/mustache/java/compiler/0.9.3/compiler-0.9.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/percolator-client/6.3.2/percolator-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/parent-join-client/6.3.2/parent-join-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/elasticsearch/plugin/rank-eval-client/6.3.2/rank-eval-client-6.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/log4j/log4j/1.2.17/log4j-1.2.17.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.11.0/log4j-api-2.11.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-core/2.11.0/log4j-core-2.11.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/nutz/nutz/1.r.68-SNAPSHOT/nutz-1.r.68-SNAPSHOT.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" enabled="true" runInBatchMode="false"/>
</factorypath>

View File

@ -0,0 +1,39 @@
<?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>
<parent>
<artifactId>nutzboot-demo-simple</artifactId>
<groupId>org.nutz</groupId>
<version>2.3.7-SNAPSHOT</version>
</parent>
<artifactId>nutzboot-demo-simple-jetty-sessionstore</artifactId>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-mvc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-dao</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,44 @@
package io.nutz.demo.simple;
import javax.servlet.http.HttpSession;
import org.nutz.boot.NbApp;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@IocBean
public class MainLauncher {
private static final Log log = Logs.get();
@Ok("raw")
@At("/time/now")
public long now() {
return System.currentTimeMillis();
}
@Ok("json:full")
@At("/session/id")
public NutMap sessionId(HttpSession session) {
if (session.isNew()) {
session.setAttribute("nutzboot", "sayhi");
}
return new NutMap("id", session.getId()).setv("time", System.currentTimeMillis());
}
@Ok("void")
@At("/session/invalidate")
public void sessionInvalidate(HttpSession session) {
session.invalidate();
}
public static void main(String[] args) throws Exception {
log.warn("本demo需要mysql数据库!!!! 详情看application.properties");
new NbApp().setPrintProcDoc(true).run();
}
}

View File

@ -0,0 +1,70 @@
package io.nutz.demo.simple;
import java.io.IOException;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.nutz.boot.starter.WebFilterFace;
import org.nutz.ioc.loader.annotation.IocBean;
@IocBean
public class Page404Filter implements WebFilterFace, Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
HttpServletResponse resp = (HttpServletResponse)response;
if (resp.getStatus() == 404) {
// 打印日志
}
}
@Override
public void destroy() {
}
@Override
public String getName() {
return "page404";
}
@Override
public String getPathSpec() {
return "/*";
}
@Override
public EnumSet<DispatcherType> getDispatches() {
return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, DispatcherType.FORWARD);
}
@Override
public Filter getFilter() {
return this;
}
@Override
public Map<String, String> getInitParameters() {
return new HashMap<>();
}
@Override
public int getOrder() {
return 0;
}
}

View File

@ -0,0 +1,24 @@
package io.nutz.demo.simple.handler;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
@IocBean
public class MyHandler extends ErrorPageErrorHandler {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException {
if(response.getStatus() == 404){
response.getWriter().write(Json.toJson(new NutMap("code","-1").setv("msg","404 error")));
return;
}
super.handle(target, baseRequest, request, response);
}
}

View File

@ -0,0 +1,35 @@
package io.nutz.demo.simple.service;
import java.util.concurrent.atomic.AtomicLong;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
@IocBean
public class OrderService {
private static final Log log = Logs.get();
// 假装有库存
protected AtomicLong store = new AtomicLong(100);
public boolean buy(int number) {
// 购买数量不合法,直接返还false咯
if (number < 1)
return false;
// 减少库存
long after = store.addAndGet(0 - number);
if (after >= 0) {
// 减少之后依然有剩余,那就购买成功咯
log.info("购买成功");
return true;
}
else {
// 减少之后库存是负数了,购买失败咯,返还库存
store.addAndGet(number);
log.info("购买失败");
return false;
}
}
}

View File

@ -0,0 +1,47 @@
package io.nutz.demo.simple.websocket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.websocket.EndpointConfig;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint;
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
import org.nutz.plugins.mvc.websocket.WsHandler;
import io.nutz.demo.simple.service.OrderService;
@ServerEndpoint(value = "/websocket", configurator=NutWsConfigurator.class)
@IocBean(create="init", depose="depose") // 使用NutWsConfigurator的必备条件
public class MyWebSocket extends AbstractWsEndpoint {
@Inject("refer:$ioc")
protected Ioc ioc;
@Inject
protected OrderService orderService;
protected ExecutorService es;
public WsHandler createHandler(Session session, EndpointConfig config) {
return new MyWsHandler(ioc, orderService, es);
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public void init() {
es = Executors.newFixedThreadPool(16);
}
public void depose() {
if (es != null)
es.shutdown();
}
}

View File

@ -0,0 +1,57 @@
package io.nutz.demo.simple.websocket;
import java.util.concurrent.ExecutorService;
import javax.servlet.http.HttpSession;
import org.nutz.ioc.Ioc;
import org.nutz.lang.util.NutMap;
import org.nutz.plugins.mvc.websocket.handler.SimpleWsHandler;
import io.nutz.demo.simple.service.OrderService;
public class MyWsHandler extends SimpleWsHandler {
protected Ioc ioc;
protected OrderService orderService;
protected ExecutorService es;
public MyWsHandler(Ioc ioc, OrderService orderService, ExecutorService es) {
super();
this.ioc = ioc;
this.orderService = orderService;
this.es = es;
}
// AbstractWsEndpoint会设置session/httpSession/endpoint实例,然后调用这个init
// 换句话说,调用init的时候, 上面的对象已经准备好了,可以直接用
@Override
public void init() {
super.init();
// HttpSession是req/resp用到的Session, 与WebSocket Session不是同一个
if (httpSession != null) {
// 有时候,其他service/action方法,需要往websocekt主动传输数据
// 传输数据用到endpoint实例的send方法均需要带上websocket的id
// 这里演示,总是把最新的websocekt session id设置到http session里面
// 真实场景中, 可能存在一个HttpSession带N个WebSocket Session的情况
// 这时候可以考虑用Set<String>或者数据库存储的方式解决
httpSession.setAttribute("wsid_last", session.getId());
}
}
// 对应js代码 ws.send('{action:"buy", order:1}')
public void buy(NutMap params) {
// 先检查一下参数
Number n = params.getAs("order", Number.class);
if (n == null) {
// 没提过数量就拒绝咯
endpoint.sendJson(session.getId(), new NutMap("ok", false).setv("msg", "没有提供数量"));
}
else {
// 返回处理结果
boolean re = orderService.buy(n.intValue());
endpoint.sendJson(session.getId(), new NutMap("ok", re));
}
}
}

View File

@ -0,0 +1,14 @@
server.port=8080
server.host=0.0.0.0
jetty.threadpool.idleTimeout=60000
jetty.threadpool.minThreads=4
jetty.threadpool.maxThreads=8
jetty.page.404=/404.html
jetty.page.500=/500.html
jetty.session.store.enable=true
jetty.session.store.type=jdbc
jdbc.url=jdbc:mysql://127.0.0.1:3306/jettysession
jdbc.username=root
jdbc.password=root

View File

@ -0,0 +1,7 @@
log4j.rootLogger=debug,Console
log4j.logger.org.eclipse.jetty=info
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%-5p] %d{HH:mm:ss.SSS} %l - %m%n

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
this is 404 page!
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
this is 500 page!
</body>
</html>

View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Hello, So NB!</title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body style="background-color: #30bded;">
<div class="container-fluid">
<div class="row" id="app">
<div class="col-md-2"></div>
<div class="col-md-8">
<div class="row">
<h3>session持久化测试, session数据每2秒刷新一次, 请尝试开启和关闭进程, 观察获取到的session id是否相同</h3>
</div>
<div class="row">
<p>当前SessionId: <a href="#">{{sessionId}}</a>
</div>
<div class="row">
<p>当前Session状态: <a href="#">{{sessionStatus}}</a>
</div>
<div class="row">
<button class="btn-default" @click="doClose()">注销并获取新的Session</button>
</div>
</div>
<div class="col-md-2"></div>
</div>
</div>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
<script type="text/javascript">
var _app = new Vue({
el : "#app",
data : {
timeNow : 0,
sessionId : "未知",
sessionStatus : "未知"
},
methods : {
dataReload : function() {
$.ajax({
url : "session/id",
dataType : "json",
success : function(re) {
_app.sessionId = re.id;
_app.sessionStatus = "已获取"
_app.time = re.time;
},
error : function(re) {
_app.sessionId = "未知";
_app.sessionStatus = "连接服务器失败"
}
})
},
doClose : function() {
$.ajax({
url : "session/invalidate",
success : function(re) {
_app.dataReload();
}
})
}
}
});
setInterval(_app.dataReload, 1000);
</script>
</html>

View File

@ -60,6 +60,7 @@
<module>nutzboot-demo-simple-sqlxmltpl</module>
<module>nutzboot-demo-simple-thymeleaf-shiro</module>
<module>nutzboot-demo-simple-redisson</module>
<module>nutzboot-demo-simple-jetty-sessionstore</module>
</modules>
<dependencies>

View File

@ -9,6 +9,7 @@ import java.util.Enumeration;
import java.util.List;
import java.util.zip.Deflater;
import javax.sql.DataSource;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpoint;
@ -19,6 +20,13 @@ import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.session.DatabaseAdaptor;
import org.eclipse.jetty.server.session.DefaultSessionCache;
import org.eclipse.jetty.server.session.FileSessionDataStoreFactory;
import org.eclipse.jetty.server.session.JDBCSessionDataStoreFactory;
import org.eclipse.jetty.server.session.SessionCache;
import org.eclipse.jetty.server.session.SessionDataStore;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
@ -131,6 +139,18 @@ public class JettyStarter extends AbstractServletContainerStarter implements Ser
public static final String PROP_HTTPS_KEYSTORE_PATH = PRE + "https.keystore.path";
@PropDoc(value = "Https的KeyStore的密码")
public static final String PROP_HTTPS_KEYSTORE_PASSWORD = PRE + "https.keystore.password";
// Session持久化相关
@PropDoc(value = "是否启用session持久化", defaultValue="false")
public static final String PROP_SESSION_STORE_ENABLE = PRE + "session.store.enable";
@PropDoc(value = "session持久化类型", defaultValue="jdbc", possible= {"jdbc", "file", "ioc", "redis"})
public static final String PROP_SESSION_STORE_TYPE = PRE + "session.store.type";
@PropDoc(value = "session持久化,jdbc所用数据库源的ioc名称", defaultValue="dataSource")
public static final String PROP_SESSION_JDBC_DATASOURCE_IOCNAME = PRE + "session.jdbc.datasource.iocname";
@PropDoc(value = "session持久化,file所用的目录", defaultValue="./session")
public static final String PROP_SESSION_FILE_STOREDIR = PRE + "session.file.storeDir";
@PropDoc(value = "session持久化,SessionDataStore对应的ioc名称", defaultValue="jettySessionDataStore")
public static final String PROP_SESSION_IOC_DATASTORE = PRE + "session.ioc.datastore";
protected Server server;
protected WebAppContext wac;
@ -308,6 +328,45 @@ public class JettyStarter extends AbstractServletContainerStarter implements Ser
sc.addEndpoint(klass);
}
}
// 试试session持久化
if (conf.getBoolean(PROP_SESSION_STORE_ENABLE)) {
SessionHandler handler = wac.getSessionHandler();
SessionCache sessionCache = new DefaultSessionCache(handler);
String type = conf.get(PROP_SESSION_STORE_TYPE, "jdbc");
log.info("using session store, type=" + type);
switch (type) {
case "jdbc":
{
JDBCSessionDataStoreFactory factory = new JDBCSessionDataStoreFactory();
DatabaseAdaptor adaptor = new DatabaseAdaptor();
adaptor.setDatasource(ioc.get(DataSource.class, conf.get(PROP_SESSION_JDBC_DATASOURCE_IOCNAME, "dataSource")));
factory.setDatabaseAdaptor(adaptor);
sessionCache.setSessionDataStore(factory.getSessionDataStore(handler));
break;
}
case "file":
{
FileSessionDataStoreFactory factory = new FileSessionDataStoreFactory();
factory.setStoreDir(new File(conf.get(PROP_SESSION_FILE_STOREDIR, "./sessions")));
sessionCache.setSessionDataStore(factory.getSessionDataStore(handler));
break;
}
case "ioc":
{
sessionCache.setSessionDataStore(ioc.get(SessionDataStore.class, conf.get(PROP_SESSION_IOC_DATASTORE, "jettySessionDataStore")));
break;
}
case "redis":
{
// 未完成...
}
default:
log.warn("not support yet, type=" + type);
break;
}
handler.setSessionCache(sessionCache);
}
}
private void addNutzSupport() {