Last active
August 29, 2015 13:56
-
-
Save PauloMigAlmeida/8919982 to your computer and use it in GitHub Desktop.
Steps to make you app and database work with utf8mb4 characters in order to accept emojis. It's based on a webapp using Maven+Hibernate+Spring+Jetty+MySQL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AppDelegate.m | |
// | |
// Created by andre.michels on 12/3/13. | |
// | |
#import "AppDelegate.h" | |
#import "NetworkAvailabilityUtils.h" | |
@implementation TableViewHistoryAppDelegate | |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |
{ | |
// Override point for customization after application launch. | |
//Initializing Network Observer | |
[NetworkAvailabilityUtils instance]; | |
return YES; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// BaseNetworkRequest.h | |
// | |
// Created by Paulo Almeida on 12/9/13. | |
// | |
#import <Foundation/Foundation.h> | |
@protocol BaseNetworkDelegate <NSObject> | |
-(void) sucessOnRequest:(NSDictionary*) jsonArray AndIdentifier:(NSString*) identifier; | |
-(void) errorOnRequest:(NSString*) identifier; | |
-(void) noConnectivity; | |
@end | |
@interface BaseNetworkRequest : NSObject | |
#pragma Properties | |
@property (nonatomic, strong) NSURL *url; | |
@property (nonatomic,strong) id <BaseNetworkDelegate> delegate; | |
@property (nonatomic,strong) NSString* identifier; | |
#pragma Methods | |
-(void) startGetRequest; | |
-(void) startPostRequest:(NSData*)postBody; | |
-(void) startPostMultipartDataRequest:(NSDictionary *)postParameters; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// BaseNetworkRequest.m | |
// now | |
// | |
// Created by Paulo Almeida on 12/9/13. | |
// Copyright (c) 2013 Loducca. All rights reserved. | |
// | |
#import "BaseNetworkRequest.h" | |
#import "NetworkAvailabilityUtils.h" | |
@implementation BaseNetworkRequest | |
-(void) startGetRequest | |
{ | |
if(![NetworkAvailabilityUtils isConnected]){ | |
[self.delegate noConnectivity]; | |
return; | |
} | |
NSURLRequest *request = [NSURLRequest requestWithURL:[self url]]; | |
[NSURLConnection sendAsynchronousRequest:request queue: [NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) | |
{ | |
if(error) | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else | |
{ | |
if([data length]>0) | |
{ | |
NSError *error = nil; | |
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; | |
if (error != nil) { | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else { | |
NSNumber *code = [jsonArray objectForKey:@"code"]; | |
if([code intValue] == 0) | |
{ | |
//NSLog(@"Array: %@", jsonArray); | |
[self.delegate sucessOnRequest:jsonArray AndIdentifier:[self identifier]]; | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
}]; | |
} | |
-(void) startPostRequest:(NSData *)postBody | |
{ | |
if(![NetworkAvailabilityUtils isConnected]){ | |
[self.delegate noConnectivity]; | |
return; | |
} | |
NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[self url]]; | |
[postRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; | |
[postRequest setValue:[NSString | |
stringWithFormat:@"%lu", (unsigned long)[postBody length]] | |
forHTTPHeaderField:@"Content-length"]; | |
[postRequest setHTTPMethod:@"POST"]; | |
[postRequest setHTTPBody:postBody]; | |
[NSURLConnection sendAsynchronousRequest:postRequest queue: [NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) | |
{ | |
if(error) | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else | |
{ | |
if([data length]>0) | |
{ | |
//NSLog(@"Return from Server: %@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); | |
NSError *error = nil; | |
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; | |
if (error != nil) { | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else { | |
NSNumber *code = [jsonArray objectForKey:@"code"]; | |
if([code intValue] == 0) | |
{ | |
NSLog(@"Array: %@", jsonArray); | |
[self.delegate sucessOnRequest:jsonArray AndIdentifier:[self identifier]]; | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
}]; | |
} | |
-(void) startPostMultipartDataRequest:(NSDictionary *)postParameters | |
{ | |
if(![NetworkAvailabilityUtils isConnected]){ | |
[self.delegate noConnectivity]; | |
return; | |
} | |
NSMutableURLRequest *postRequest = [NSMutableURLRequest requestWithURL:[self url]]; | |
NSString *boundary = @"---------------------------14737809831466499882746641449"; | |
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; | |
[postRequest setValue:contentType forHTTPHeaderField:@"Content-Type"]; | |
NSMutableData *postbody = [NSMutableData data]; | |
NSEnumerator *enumerator = [postParameters keyEnumerator]; | |
id key; | |
while ((key = [enumerator nextObject])) { | |
NSObject *tmp = [postParameters objectForKey:key]; | |
if([tmp isKindOfClass:[NSData class]]){ | |
[postbody appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@.jpg\"\r\n", key,key] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postbody appendData:[[NSString stringWithFormat:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postbody appendData:[NSData dataWithData:[postParameters objectForKey:key]]]; | |
[postbody appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; | |
}else{ | |
[postbody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postbody appendData:[[NSString stringWithFormat:@"%@\r\n", [postParameters objectForKey:key]] dataUsingEncoding:NSUTF8StringEncoding]]; | |
} | |
} | |
[postbody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; | |
[postRequest setHTTPMethod:@"POST"]; | |
[postRequest setHTTPBody:postbody]; | |
NSString *postLength = [NSString stringWithFormat:@"%d", (int)[postbody length]]; | |
[postRequest setValue:postLength forHTTPHeaderField:@"Content-Length"]; | |
[NSURLConnection sendAsynchronousRequest:postRequest queue: [NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) | |
{ | |
if(error) | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else | |
{ | |
if([data length]>0) | |
{ | |
NSError *error = nil; | |
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; | |
if (error != nil) { | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
else { | |
NSNumber *code = [jsonArray objectForKey:@"code"]; | |
if([code intValue] == 0) | |
{ | |
//NSLog(@"Array: %@", jsonArray); | |
[self.delegate sucessOnRequest:jsonArray AndIdentifier:[self identifier]]; | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
} | |
else | |
{ | |
[self.delegate errorOnRequest:[self identifier]]; | |
} | |
} | |
}]; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.github.gist.utf8mb4.domain; | |
import org.hibernate.annotations.SQLDelete; | |
import org.hibernate.annotations.Where; | |
import javax.validation.Valid; | |
import javax.validation.constraints.NotNull; | |
import javax.validation.constraints.Size; | |
import javax.persistence.*; | |
import java.util.Date; | |
@Entity | |
@SQLDelete(sql = "UPDATE Comment SET dateRemoval = CURRENT_TIMESTAMP() WHERE id = ?") | |
@Where(clause = "dateRemoval is null") | |
public class Comment { | |
private static final long serialVersionUID = 1L; | |
@Id | |
@GeneratedValue(strategy = GenerationType.IDENTITY) | |
private Integer id; | |
@ManyToOne(targetEntity = User.class) | |
@Valid | |
@NotNull | |
private User user; | |
@Column(length = 400, nullable = false) | |
@NotNull | |
@Size(min = 1, max = 400) | |
private String text; | |
@Column(insertable = true, updatable = false) | |
@Temporal(TemporalType.TIMESTAMP) | |
private Date dateInsertion; | |
@Column(insertable = false, updatable = false) | |
@Temporal(TemporalType.TIMESTAMP) | |
private Date dateRemoval; | |
public Comment() { | |
} | |
//Getters and Setters | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NSString *postData = [NSString stringWithFormat:@"text=%@",_homeTextComment.text ]; | |
BaseNetworkRequest *insertCommentRequest = [[BaseNetworkRequest alloc] init]; | |
[insertCommentRequest setDelegate:self]; | |
[insertCommentRequest setUrl:[NSURL URLWithString:[Constants COMMENT_INSERT_SERVICE]]]; | |
[insertCommentRequest setIdentifier:@"insertCommentRequest"]; | |
[insertCommentRequest startPostRequest:[postData dataUsingEncoding:NSUTF8StringEncoding]]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
This file must be place within src/main/webapp/WEB-INF/jetty-env.xml | |
--> | |
<?xml version="1.0"?> | |
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext"> | |
<New id="jdbc/ds" class="org.eclipse.jetty.plus.jndi.Resource"> | |
<Arg>jdbc/now</Arg> | |
<Arg> | |
<New class="org.apache.commons.dbcp.BasicDataSource"> | |
<Set name="driverClassName">com.mysql.jdbc.Driver</Set> | |
<Set name="url">jdbc:mysql://<yourhost>:3306/<db> | |
</Set> | |
<Set name="username">yourusername</Set> | |
<Set name="password">yourpass</Set> | |
<Set name="initialSize">10</Set> | |
<Set name="maxActive">20</Set> | |
<Set name="maxIdle">15</Set> | |
</New> | |
</Arg> | |
</New> | |
</Configure> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Add the following lines to your my.cnf file | |
[mysqld] | |
character-set-client-handshake = FALSE | |
character-set-server = utf8mb4 | |
collation-server = utf8mb4_unicode_ci |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NetworkAvailabilityUtils.h | |
// | |
// Created by Paulo Almeida on 12/10/13. | |
// | |
#import <Foundation/Foundation.h> | |
#import "Reachability.h" | |
@interface NetworkAvailabilityUtils : NSObject | |
@property (nonatomic,strong) Reachability *reachability ; | |
+(NetworkAvailabilityUtils*) instance; | |
+(BOOL) isConnected; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NetworkAvailabilityUtils.m | |
// | |
// Created by Paulo Almeida on 12/10/13. | |
// | |
#import "NetworkAvailabilityUtils.h" | |
@implementation NetworkAvailabilityUtils | |
static NetworkAvailabilityUtils *instance; | |
static bool isConnected; | |
+(NetworkAvailabilityUtils*) instance | |
{ | |
if(instance == NULL) | |
{ | |
instance = [[self alloc]init]; | |
} | |
return instance; | |
} | |
+(BOOL) isConnected | |
{ | |
return isConnected; | |
} | |
- (id)init { | |
if ( (self = [super init]) ) { | |
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChanged:) name:kReachabilityChangedNotification object:nil]; | |
_reachability = [Reachability reachabilityForInternetConnection]; | |
[_reachability startNotifier]; | |
//Perform a first check in order to get the actual scenario | |
[self networkChanged:nil]; | |
} | |
return self; | |
} | |
- (void)networkChanged:(NSNotification *)notification | |
{ | |
NetworkStatus remoteHostStatus = [_reachability currentReachabilityStatus]; | |
if(remoteHostStatus == NotReachable) | |
{ | |
NSLog(@"not reachable"); | |
isConnected = NO; | |
} | |
else if (remoteHostStatus == ReachableViaWiFi) | |
{ | |
NSLog(@"wifi"); | |
isConnected = YES; | |
} | |
else if (remoteHostStatus == ReachableViaWWAN) | |
{ | |
NSLog(@"carrier"); | |
isConnected = YES; | |
} | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
To run this application using command line: mvn clean compile package jetty:run -DskipTests -Pjetty | |
--> | |
<?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/maven-v4_0_0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.github.gist</groupId> | |
<artifactId>utf8mb4example</artifactId> | |
<packaging>war</packaging> | |
<version>1.0</version> | |
<properties> | |
<configuration.source>1.6</configuration.source> | |
<configuration.target>1.6</configuration.target> | |
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | |
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
<org.springframework.version>3.1.1.RELEASE</org.springframework.version> | |
<com.google.code.gson.gson.version>1.7.1</com.google.code.gson.gson.version> | |
</properties> | |
<dependencies> | |
<!-- Jackson JSON Mapper --> | |
<dependency> | |
<groupId>org.codehaus.jackson</groupId> | |
<artifactId>jackson-mapper-asl</artifactId> | |
<version>1.5.3</version> | |
</dependency> | |
<!-- Servlet API --> | |
<dependency> | |
<groupId>org.mortbay.jetty</groupId> | |
<artifactId>servlet-api-2.5</artifactId> | |
<version>6.1.11</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>jsp-api</artifactId> | |
<version>2.0</version> | |
<scope>provided</scope> | |
</dependency> | |
<!-- JSON to Java Converter --> | |
<dependency> | |
<groupId>com.google.code.gson</groupId> | |
<artifactId>gson</artifactId> | |
<version>${com.google.code.gson.gson.version}</version> | |
</dependency> | |
<!-- Spring framework --> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-web</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-webmvc</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.security</groupId> | |
<artifactId>spring-security-core</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.security</groupId> | |
<artifactId>spring-security-web</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.security</groupId> | |
<artifactId>spring-security-config</artifactId> | |
<version>${org.springframework.version}</version> | |
</dependency> | |
<!-- JUnit --> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>3.8.1</version> | |
<scope>test</scope> | |
</dependency> | |
<!-- JSTL --> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>jstl</artifactId> | |
<version>1.1.2</version> | |
</dependency> | |
<dependency> | |
<groupId>taglibs</groupId> | |
<artifactId>standard</artifactId> | |
<version>1.1.2</version> | |
</dependency> | |
</dependencies> | |
<profiles> | |
<profile> | |
<id>jetty</id> | |
<dependencies> | |
<dependency> | |
<groupId>commons-dbcp</groupId> | |
<artifactId>commons-dbcp</artifactId> | |
<version>1.2</version> | |
</dependency> | |
<dependency> | |
<groupId>mysql</groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
<version>5.1.28</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<plugins> | |
<plugin> | |
<groupId>org.eclipse.jetty</groupId> | |
<artifactId>jetty-maven-plugin</artifactId> | |
<version>9.1.0.M0</version> | |
<configuration> | |
<webAppConfig> | |
<contextPath>/</contextPath> | |
</webAppConfig> | |
<systemProperties> | |
<systemProperty> | |
<name>org.mortbay.util.URI.charset</name> | |
<value>UTF-8</value> | |
</systemProperty> | |
</systemProperties> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</profile> | |
</profiles> | |
<build> | |
<plugins> | |
<plugin> | |
<artifactId>maven-compiler-plugin</artifactId> | |
<version>2.0.2</version> | |
<configuration> | |
<source>${configuration.source}</source> | |
<target>${configuration.target}</target> | |
</configuration> | |
</plugin> | |
</plugins> | |
<finalName>${project.artifactId}</finalName> | |
</build> | |
</project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ALTER DATABASE db | |
DEFAULT CHARACTER SET utf8mb4 | |
DEFAULT COLLATE utf8mb4_unicode_ci; | |
ALTER TABLE Comment CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY COLUMN text varchar(400) CHARACTER SET utf8mb4 ; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" | |
version="3.0"> | |
<display-name>WebApp</display-name> | |
<context-param> | |
<param-name>contextConfigLocation</param-name> | |
<param-value>/WEB-INF/security-context.xml</param-value> | |
</context-param> | |
<listener> | |
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> | |
</listener> | |
<listener> | |
<listener-class> | |
org.springframework.web.context.request.RequestContextListener | |
</listener-class> | |
</listener> | |
<!-- Filter Encoding --> | |
<filter> | |
<filter-name>encoding-filter</filter-name> | |
<filter-class> | |
org.springframework.web.filter.CharacterEncodingFilter | |
</filter-class> | |
<init-param> | |
<param-name>encoding</param-name> | |
<param-value>UTF-8</param-value> | |
</init-param> | |
<init-param> | |
<param-name>forceEncoding</param-name> | |
<param-value>true</param-value> | |
</init-param> | |
</filter> | |
<filter-mapping> | |
<filter-name>encoding-filter</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping> | |
<!-- Filter Config --> | |
<filter> | |
<filter-name>springSecurityFilterChain</filter-name> | |
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> | |
</filter> | |
<!-- Filter Mappings --> | |
<filter-mapping> | |
<filter-name>springSecurityFilterChain</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping> | |
<servlet> | |
<servlet-name>spring</servlet-name> | |
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> | |
<load-on-startup>1</load-on-startup> | |
</servlet> | |
<servlet-mapping> | |
<servlet-name>spring</servlet-name> | |
<url-pattern>*.action</url-pattern> | |
</servlet-mapping> | |
<resource-ref> | |
<description>DataSource</description> | |
<res-ref-name>jdbc/ds</res-ref-name> | |
<res-type>javax.sql.DataSource</res-type> | |
<res-auth>Container</res-auth> | |
</resource-ref> | |
</web-app> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment