├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── zbum │ │ └── example │ │ └── socket │ │ └── server │ │ ├── Application.java │ │ ├── netty │ │ ├── ChannelRepository.java │ │ ├── TCPServer.java │ │ └── handler │ │ │ ├── SomethingChannelInitializer.java │ │ │ └── SomethingServerHandler.java │ │ └── repository │ │ ├── RepositoryConfiguration.java │ │ ├── User.java │ │ └── UserRepository.java └── resources │ ├── logback.xml │ ├── properties.production │ ├── nettyserver.properties │ └── springjpa.properties │ └── properties │ └── local │ ├── nettyserver.properties │ └── springjpa.properties └── test └── java └── com └── zbum └── example └── socket └── server ├── netty └── handler │ └── SomethingServerHandlerTest.java └── repository └── UserRepositoryTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | target/ 3 | netty-spring-with-jpa.iml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netty-spring-example with JPA 2 | TCP communication server with Netty, spring-boot, spring-data-jpa 3 | 4 | This TCP Communication Service is a simple example for developer who want to make tcp service with Spring-Boot, Spring-Data-JPA and Netty. 5 | 6 | ## Feature 7 | * Telnet Client can send message to other telnet client. 8 | * Telnet Client can retrieve User Information from RDBMS(H2 DB). 9 | 10 | ## Install 11 | This example uses embedded DBMS(h2 db). So, you don't need to install any DBMS. 12 | But you have to use below DDL and DML. 13 | 14 | ```sql 15 | CREATE TABLE USER 16 | ( 17 | ID BIGINT AUTO_INCREMENT PRIMARY KEY NOT NULL, 18 | PHONE_NUMBER VARCHAR(255), 19 | USERNAME VARCHAR(255), 20 | USE_YN BOOLEAN DEFAULT TRUE 21 | ); 22 | CREATE UNIQUE INDEX UK_SB8BBOUER5WAK8VYIIY4PF2BX_INDEX_2 ON USER (USERNAME); 23 | ``` 24 | 25 | ```sql 26 | INSERT INTO PUBLIC.USER (ID, PHONE_NUMBER, USERNAME, USE_YN) VALUES (1, '010-1111-2222', 'zbum', true); 27 | INSERT INTO PUBLIC.USER (ID, PHONE_NUMBER, USERNAME, USE_YN) VALUES (2, '010-1111-3333', 'manty', true); 28 | INSERT INTO PUBLIC.USER (ID, PHONE_NUMBER, USERNAME, USE_YN) VALUES (3, '010-1111-4444', 'jibumjung', true); 29 | ``` 30 | 31 | ## How to use 32 | * Run com.zbum.example.socket.server.netty.Application with IDE or Maven 33 | ``` 34 | $ mvn spring-boot:run 35 | ``` 36 | * Connect to this server by telnet command. 37 | ``` 38 | $ telnet localhost 8090 39 | Trying ::1... 40 | Connected to localhost. 41 | Escape character is '^]'. 42 | Your channel key is /0:0:0:0:0:0:0:1:57220 43 | ``` 44 | * Your channel key (ID) is /0:0:0:0:0:0:0:1:57220 45 | * Connect to this server by telnet command on annother terminal. 46 | ``` 47 | $ telnet localhost 8090 48 | Trying ::1... 49 | Connected to localhost. 50 | Escape character is '^]'. 51 | Your channel key is /0:0:0:0:0:0:0:1:57221 52 | ``` 53 | * From now, you can send message to /0:0:0:0:0:0:0:1:57220 channel by below 54 | ``` 55 | /0:0:0:0:0:0:0:1:57220::I Love You!!! 56 | ``` 57 | * Then, you can receive Message like below 58 | ```bash 59 | $ telnet localhost 8090 60 | Trying ::1... 61 | Connected to localhost. 62 | Escape character is '^]'. 63 | Your channel key is /0:0:0:0:0:0:0:1:57220 64 | I Love You!!! 65 | ``` 66 | 67 | * Then, you can retrieve user data by command below. 68 | ```bash 69 | $ telnet localhost 8090 70 | Trying ::1... 71 | Connected to localhost. 72 | Escape character is '^]'. 73 | Your channel key is /0:0:0:0:0:0:0:1:63390 74 | name?zbum 75 | 010-1111-2222 76 | name?manty 77 | 010-1111-3333 78 | name?all 79 | zbum:010-1111-2222 80 | manty:010-1111-3333 81 | ``` -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.zbum.example.socket.server 8 | netty-spring-example-with-jpa 9 | 1.0-SNAPSHOT 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 1.2.5.RELEASE 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-data-jpa 20 | 21 | 22 | io.netty 23 | netty-all 24 | 4.0.28.Final 25 | compile 26 | 27 | 28 | 29 | com.h2database 30 | h2 31 | 1.3.176 32 | 33 | 34 | 35 | junit 36 | junit 37 | 4.8.1 38 | test 39 | 40 | 41 | org.mockito 42 | mockito-core 43 | 2.0.31-beta 44 | test 45 | 46 | 47 | org.springframework 48 | spring-test 49 | 4.0.4.RELEASE 50 | test 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server; 17 | 18 | import com.zbum.example.socket.server.netty.ChannelRepository; 19 | import com.zbum.example.socket.server.netty.TCPServer; 20 | import com.zbum.example.socket.server.netty.handler.SomethingChannelInitializer; 21 | import io.netty.bootstrap.ServerBootstrap; 22 | import io.netty.channel.ChannelOption; 23 | import io.netty.channel.nio.NioEventLoopGroup; 24 | import io.netty.channel.socket.nio.NioServerSocketChannel; 25 | import io.netty.handler.logging.LogLevel; 26 | import io.netty.handler.logging.LoggingHandler; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.beans.factory.annotation.Qualifier; 29 | import org.springframework.beans.factory.annotation.Value; 30 | import org.springframework.boot.SpringApplication; 31 | import org.springframework.boot.autoconfigure.SpringBootApplication; 32 | import org.springframework.context.ConfigurableApplicationContext; 33 | import org.springframework.context.annotation.*; 34 | 35 | import java.net.InetSocketAddress; 36 | import java.util.HashMap; 37 | import java.util.Map; 38 | import java.util.Set; 39 | 40 | /** 41 | * Spring Java Configuration and Bootstrap 42 | * 43 | * @author Jibeom Jung 44 | */ 45 | @SpringBootApplication 46 | @ComponentScan(basePackages = "com.zbum.example") 47 | @PropertySource(value= "classpath:/properties/local/nettyserver.properties") 48 | public class Application { 49 | 50 | @Configuration 51 | @Profile("production") 52 | @PropertySource("classpath:/properties/production/nettyserver.properties") 53 | static class Production 54 | { } 55 | 56 | @Configuration 57 | @Profile("local") 58 | @PropertySource({"classpath:/properties/local/nettyserver.properties"}) 59 | static class Local 60 | { } 61 | 62 | public static void main(String[] args) throws Exception{ 63 | ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args); 64 | ctx.getBean(TCPServer.class).start(); 65 | } 66 | 67 | @Value("${tcp.port}") 68 | private int tcpPort; 69 | 70 | @Value("${boss.thread.count}") 71 | private int bossCount; 72 | 73 | @Value("${worker.thread.count}") 74 | private int workerCount; 75 | 76 | @Value("${so.keepalive}") 77 | private boolean keepAlive; 78 | 79 | @Value("${so.backlog}") 80 | private int backlog; 81 | 82 | @SuppressWarnings("unchecked") 83 | @Bean(name = "serverBootstrap") 84 | public ServerBootstrap bootstrap() { 85 | ServerBootstrap b = new ServerBootstrap(); 86 | b.group(bossGroup(), workerGroup()) 87 | .channel(NioServerSocketChannel.class) 88 | .handler(new LoggingHandler(LogLevel.DEBUG)) 89 | .childHandler(somethingChannelInitializer); 90 | Map, Object> tcpChannelOptions = tcpChannelOptions(); 91 | Set> keySet = tcpChannelOptions.keySet(); 92 | for (@SuppressWarnings("rawtypes") ChannelOption option : keySet) { 93 | b.option(option, tcpChannelOptions.get(option)); 94 | } 95 | return b; 96 | } 97 | 98 | @Autowired 99 | @Qualifier("somethingChannelInitializer") 100 | private SomethingChannelInitializer somethingChannelInitializer; 101 | 102 | @Bean(name = "tcpChannelOptions") 103 | public Map, Object> tcpChannelOptions() { 104 | Map, Object> options = new HashMap, Object>(); 105 | options.put(ChannelOption.SO_KEEPALIVE, keepAlive); 106 | options.put(ChannelOption.SO_BACKLOG, backlog); 107 | return options; 108 | } 109 | 110 | @Bean(name = "bossGroup", destroyMethod = "shutdownGracefully") 111 | public NioEventLoopGroup bossGroup() { 112 | return new NioEventLoopGroup(bossCount); 113 | } 114 | 115 | @Bean(name = "workerGroup", destroyMethod = "shutdownGracefully") 116 | public NioEventLoopGroup workerGroup() { 117 | return new NioEventLoopGroup(workerCount); 118 | } 119 | 120 | @Bean(name = "tcpSocketAddress") 121 | public InetSocketAddress tcpPort() { 122 | return new InetSocketAddress(tcpPort); 123 | } 124 | 125 | @Bean(name = "channelRepository") 126 | public ChannelRepository channelRepository() { 127 | return new ChannelRepository(); 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/netty/ChannelRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.netty; 17 | 18 | import io.netty.channel.Channel; 19 | 20 | import java.util.HashMap; 21 | 22 | /** 23 | * Channel Repository using HashMap 24 | * 25 | * @author Jibeom Jung 26 | */ 27 | public class ChannelRepository { 28 | private HashMap channelCache = new HashMap(); 29 | 30 | public ChannelRepository put(String key, Channel value) { 31 | channelCache.put(key, value); 32 | return this; 33 | } 34 | 35 | public Channel get(String key) { 36 | return channelCache.get(key); 37 | } 38 | 39 | public void remove(String key) { this.channelCache.remove(key); } 40 | 41 | public int size() { 42 | return this.channelCache.size(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/netty/TCPServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.netty; 17 | 18 | import io.netty.bootstrap.ServerBootstrap; 19 | import io.netty.channel.Channel; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.beans.factory.annotation.Qualifier; 22 | import org.springframework.stereotype.Component; 23 | 24 | import javax.annotation.PreDestroy; 25 | import java.net.InetSocketAddress; 26 | 27 | 28 | /** 29 | * Main Server 30 | * 31 | * @author Jibeom Jung 32 | */ 33 | @Component 34 | public class TCPServer { 35 | 36 | @Autowired 37 | @Qualifier("serverBootstrap") 38 | private ServerBootstrap serverBootstrap; 39 | 40 | @Autowired 41 | @Qualifier("tcpSocketAddress") 42 | private InetSocketAddress tcpPort; 43 | 44 | private Channel serverChannel; 45 | 46 | public void start() throws Exception { 47 | serverChannel = serverBootstrap.bind(tcpPort).sync().channel().closeFuture().sync().channel(); 48 | } 49 | 50 | @PreDestroy 51 | public void stop() throws Exception { 52 | serverChannel.close(); 53 | serverChannel.parent().close(); 54 | } 55 | 56 | public ServerBootstrap getServerBootstrap() { 57 | return serverBootstrap; 58 | } 59 | 60 | public void setServerBootstrap(ServerBootstrap serverBootstrap) { 61 | this.serverBootstrap = serverBootstrap; 62 | } 63 | 64 | public InetSocketAddress getTcpPort() { 65 | return tcpPort; 66 | } 67 | 68 | public void setTcpPort(InetSocketAddress tcpPort) { 69 | this.tcpPort = tcpPort; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/netty/handler/SomethingChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.netty.handler; 17 | 18 | import io.netty.channel.ChannelInboundHandlerAdapter; 19 | import io.netty.channel.ChannelInitializer; 20 | import io.netty.channel.ChannelPipeline; 21 | import io.netty.channel.socket.SocketChannel; 22 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 23 | import io.netty.handler.codec.Delimiters; 24 | import io.netty.handler.codec.string.StringDecoder; 25 | import io.netty.handler.codec.string.StringEncoder; 26 | import org.springframework.beans.factory.annotation.Autowired; 27 | import org.springframework.beans.factory.annotation.Qualifier; 28 | import org.springframework.stereotype.Component; 29 | 30 | /** 31 | * Channel Initializer 32 | * 33 | * @author Jibeom Jung 34 | */ 35 | @Component 36 | @Qualifier("somethingChannelInitializer") 37 | public class SomethingChannelInitializer extends ChannelInitializer { 38 | 39 | private static final StringDecoder DECODER = new StringDecoder(); 40 | private static final StringEncoder ENCODER = new StringEncoder(); 41 | 42 | @Autowired 43 | @Qualifier("somethingServerHandler") 44 | private ChannelInboundHandlerAdapter somethingServerHandler; 45 | 46 | @Override 47 | protected void initChannel(SocketChannel socketChannel) throws Exception { 48 | ChannelPipeline pipeline = socketChannel.pipeline(); 49 | 50 | // Add the text line codec combination first, 51 | pipeline.addLast(new DelimiterBasedFrameDecoder(1024*1024, Delimiters.lineDelimiter())); 52 | // the encoder and decoder are static as these are sharable 53 | pipeline.addLast(DECODER); 54 | pipeline.addLast(ENCODER); 55 | 56 | pipeline.addLast(somethingServerHandler); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/netty/handler/SomethingServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.netty.handler; 17 | 18 | import com.zbum.example.socket.server.netty.ChannelRepository; 19 | import com.zbum.example.socket.server.repository.User; 20 | import com.zbum.example.socket.server.repository.UserRepository; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import io.netty.channel.ChannelInboundHandlerAdapter; 24 | import org.apache.log4j.Logger; 25 | import org.springframework.beans.factory.annotation.Autowired; 26 | import org.springframework.beans.factory.annotation.Qualifier; 27 | import org.springframework.data.domain.Page; 28 | import org.springframework.data.domain.PageRequest; 29 | import org.springframework.data.domain.Sort; 30 | import org.springframework.stereotype.Component; 31 | import org.springframework.util.Assert; 32 | 33 | /** 34 | * event handler to process receiving messages 35 | * 36 | * @author Jibeom Jung 37 | */ 38 | @Component 39 | @Qualifier("somethingServerHandler") 40 | @ChannelHandler.Sharable 41 | public class SomethingServerHandler extends ChannelInboundHandlerAdapter { 42 | 43 | @Autowired 44 | private ChannelRepository channelRepository; 45 | 46 | @Autowired 47 | private UserRepository userRepository; 48 | 49 | private static Logger logger = Logger.getLogger(SomethingServerHandler.class.getName()); 50 | 51 | @Override 52 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 53 | Assert.notNull(this.channelRepository, "[Assertion failed] - ChannelRepository is required; it must not be null"); 54 | 55 | ctx.fireChannelActive(); 56 | logger.debug(ctx.channel().remoteAddress()); 57 | String channelKey = ctx.channel().remoteAddress().toString(); 58 | channelRepository.put(channelKey, ctx.channel()); 59 | 60 | ctx.writeAndFlush("Your channel key is " + channelKey + "\n\r"); 61 | 62 | logger.debug("Binded Channel Count is " + this.channelRepository.size()); 63 | } 64 | 65 | @Override 66 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 67 | String stringMessage = (String) msg; 68 | 69 | logger.debug(stringMessage); 70 | 71 | if ( stringMessage.startsWith("name?")) { 72 | String searchKeyword = stringMessage.substring(5, stringMessage.length()); 73 | logger.debug("searchKeyword is " + searchKeyword); 74 | 75 | if ( searchKeyword.equalsIgnoreCase("all")) { 76 | Page userlist = userRepository.findByUseYn(true,new PageRequest(0, 1000, new Sort(Sort.Direction.ASC, "id"))); 77 | for (User user :userlist) { 78 | ctx.channel().writeAndFlush(user.getUsername()+":"+ user.getPhoneNumber() + "\n\r"); 79 | } 80 | 81 | return; 82 | } 83 | 84 | User user = userRepository.findByUsername(searchKeyword); 85 | if ( user == null ) { 86 | ctx.channel().writeAndFlush("There is no user named " + searchKeyword + "\n\r"); 87 | }else { 88 | ctx.channel().writeAndFlush(user.getPhoneNumber() + "\n\r"); 89 | } 90 | 91 | return; 92 | } 93 | 94 | String[] splitMessage = stringMessage.split("::"); 95 | 96 | if ( splitMessage.length != 2 ) { 97 | ctx.channel().writeAndFlush(stringMessage + "\n\r"); 98 | return; 99 | } 100 | 101 | if ( channelRepository.get(splitMessage[0]) != null ) { 102 | channelRepository.get(splitMessage[0]).writeAndFlush(splitMessage[1] + "\n\r"); 103 | } 104 | 105 | 106 | } 107 | 108 | @Override 109 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 110 | logger.error(cause.getMessage(), cause); 111 | //ctx.close(); 112 | } 113 | 114 | @Override 115 | public void channelInactive(ChannelHandlerContext ctx){ 116 | Assert.notNull(this.channelRepository, "[Assertion failed] - ChannelRepository is required; it must not be null"); 117 | Assert.notNull(ctx); 118 | 119 | String channelKey = ctx.channel().remoteAddress().toString(); 120 | this.channelRepository.remove(channelKey); 121 | 122 | logger.debug("Binded Channel Count is " + this.channelRepository.size()); 123 | } 124 | 125 | public void setChannelRepository(ChannelRepository channelRepository) { 126 | this.channelRepository = channelRepository; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/repository/RepositoryConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.repository; 17 | 18 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 19 | import org.springframework.context.annotation.Configuration; 20 | import org.springframework.context.annotation.Profile; 21 | import org.springframework.context.annotation.PropertySource; 22 | 23 | /** 24 | * 25 | * @author Jibeom Jung 26 | */ 27 | @Configuration 28 | @EnableAutoConfiguration 29 | @PropertySource({"classpath:/properties/local/springjpa.properties"}) 30 | public class RepositoryConfiguration { 31 | @Configuration 32 | @Profile("production") 33 | @PropertySource("classpath:/properties/production/springjpa.properties") 34 | static class Production 35 | { } 36 | 37 | @Configuration 38 | @Profile("local") 39 | @PropertySource({"classpath:/properties/local/springjpa.properties"}) 40 | static class Local 41 | { } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/repository/User.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.repository; 17 | 18 | import org.springframework.data.jpa.domain.AbstractPersistable; 19 | 20 | import javax.persistence.Column; 21 | import javax.persistence.Entity; 22 | import javax.persistence.Table; 23 | 24 | /** 25 | * @author Jibeom Jung 26 | */ 27 | @Entity 28 | @Table(name="user") 29 | //@NamedQuery(name="User.findByTheUsername", query = "from User u where u.username=?1") 30 | public class User extends AbstractPersistable { 31 | 32 | @Column(unique=true) 33 | private String username; 34 | 35 | @Column(name="phone_number") 36 | private String phoneNumber; 37 | 38 | @Column(name="use_yn") 39 | private Boolean useYn; 40 | 41 | public User(){ 42 | this(null); 43 | } 44 | 45 | public User(Long id) { 46 | this.setId(id); 47 | } 48 | 49 | public String getUsername() { 50 | return username; 51 | } 52 | 53 | public void setUsername(String username) { 54 | this.username = username; 55 | } 56 | 57 | public String getPhoneNumber() { 58 | return phoneNumber; 59 | } 60 | 61 | public void setPhoneNumber(String phoneNumber) { 62 | this.phoneNumber = phoneNumber; 63 | } 64 | 65 | public Boolean getUseYn() { 66 | return useYn; 67 | } 68 | 69 | public void setUseYn(Boolean useYn) { 70 | this.useYn = useYn; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "User{" + 76 | "username='" + username + '\'' + 77 | ", phoneNumber='" + phoneNumber + '\'' + 78 | ", useYn=" + useYn + 79 | '}'; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/zbum/example/socket/server/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.repository; 17 | 18 | import org.springframework.data.domain.Page; 19 | import org.springframework.data.domain.Pageable; 20 | import org.springframework.data.repository.PagingAndSortingRepository; 21 | 22 | /** 23 | * @author Jibeom Jung 24 | */ 25 | public interface UserRepository extends PagingAndSortingRepository { 26 | 27 | /** 28 | * 29 | * @param username 30 | * @return 31 | */ 32 | User findByUsername(String username); 33 | 34 | Page findAll(Pageable pageable); 35 | 36 | Page findByUseYn(Boolean useYn, Pageable pageable); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/resources/properties.production/nettyserver.properties: -------------------------------------------------------------------------------- 1 | tcp.port=8090 2 | boss.thread.count=2 3 | worker.thread.count=2 4 | so.keepalive=true 5 | so.backlog=100 -------------------------------------------------------------------------------- /src/main/resources/properties.production/springjpa.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:h2:~/h2test 2 | spring.datasource.username=sa 3 | spring.datasource.password= 4 | spring.datasource.driver-class-name=org.h2.Driver 5 | 6 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 7 | spring.jpa.show-sql=true 8 | spring.jpa.hibernate.ddl-auto=create -------------------------------------------------------------------------------- /src/main/resources/properties/local/nettyserver.properties: -------------------------------------------------------------------------------- 1 | tcp.port=8090 2 | boss.thread.count=2 3 | worker.thread.count=2 4 | so.keepalive=true 5 | so.backlog=100 6 | 7 | -------------------------------------------------------------------------------- /src/main/resources/properties/local/springjpa.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:h2:~/h2test 2 | spring.datasource.username=sa 3 | spring.datasource.password= 4 | spring.datasource.driver-class-name=org.h2.Driver 5 | 6 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 7 | spring.jpa.show-sql=true 8 | spring.jpa.hibernate.ddl-auto=validate -------------------------------------------------------------------------------- /src/test/java/com/zbum/example/socket/server/netty/handler/SomethingServerHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.netty.handler; 17 | 18 | import com.zbum.example.socket.server.netty.ChannelRepository; 19 | import io.netty.channel.Channel; 20 | import io.netty.channel.ChannelHandlerContext; 21 | import org.junit.After; 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | 25 | import java.net.SocketAddress; 26 | 27 | import static org.mockito.Mockito.mock; 28 | import static org.mockito.Mockito.when; 29 | 30 | /** 31 | * Test for SomethingServerHandler.java 32 | * 33 | * @author Jibeom Jung 34 | */ 35 | public class SomethingServerHandlerTest { 36 | 37 | private SomethingServerHandler somethingServerHandler; 38 | 39 | private ChannelHandlerContext channelHandlerContext; 40 | 41 | private Channel channel; 42 | 43 | private SocketAddress remoteAddress; 44 | 45 | @Before 46 | public void setUp() throws Exception { 47 | somethingServerHandler = new SomethingServerHandler(); 48 | somethingServerHandler.setChannelRepository(new ChannelRepository()); 49 | 50 | channelHandlerContext = mock(ChannelHandlerContext.class); 51 | channel = mock(Channel.class); 52 | remoteAddress = mock(SocketAddress.class); 53 | } 54 | 55 | @After 56 | public void tearDown() throws Exception { 57 | 58 | } 59 | 60 | @Test 61 | public void testChannelActive() throws Exception { 62 | when(channelHandlerContext.channel()).thenReturn(channel); 63 | when(channelHandlerContext.channel().remoteAddress()).thenReturn(remoteAddress); 64 | somethingServerHandler.channelActive(channelHandlerContext); 65 | } 66 | 67 | @Test 68 | public void testChannelRead() throws Exception { 69 | when(channelHandlerContext.channel()).thenReturn(channel); 70 | somethingServerHandler.channelRead(channelHandlerContext, "test message"); 71 | } 72 | 73 | @Test 74 | public void testExceptionCaught() throws Exception { 75 | 76 | } 77 | } -------------------------------------------------------------------------------- /src/test/java/com/zbum/example/socket/server/repository/UserRepositoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zbum.example.socket.server.repository; 17 | 18 | import org.junit.After; 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.test.context.ContextConfiguration; 24 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 25 | import org.springframework.test.context.transaction.TransactionConfiguration; 26 | import org.springframework.transaction.annotation.Transactional; 27 | 28 | import static org.junit.Assert.assertEquals; 29 | 30 | /** 31 | * Test for SomethingServerHandler.java 32 | * 33 | * @author Jibeom Jung 34 | */ 35 | @RunWith(SpringJUnit4ClassRunner.class) 36 | @ContextConfiguration(classes = {RepositoryConfiguration.class}) 37 | @TransactionConfiguration(defaultRollback = false) 38 | @Transactional 39 | public class UserRepositoryTest { 40 | 41 | @Autowired 42 | private UserRepository userRepository; 43 | 44 | @Before 45 | public void setUp() throws Exception { 46 | 47 | } 48 | 49 | @After 50 | public void tearDown() throws Exception { 51 | 52 | } 53 | 54 | @Test 55 | public void testFindByTheUsername() throws Exception { 56 | 57 | } 58 | 59 | @Test 60 | public void testSave() throws Exception { 61 | User user = new User(1L); 62 | user.setUsername("zbum"); 63 | user.setPhoneNumber("010-1111-2222"); 64 | user.setUseYn(true); 65 | userRepository.save(user); 66 | 67 | User userRepositoryByTheUsername = userRepository.findByUsername("zbum"); 68 | assertEquals(userRepositoryByTheUsername.getPhoneNumber(), "010-1111-2222"); 69 | 70 | } 71 | } --------------------------------------------------------------------------------