Home Blog Page 77

Chuyển đổi JSON qua CSV sử dụng thư viện Jackson

json qua csv
Chuyển đổi JSON qua CSV sử dụng thư viện Jackson

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Thư viện Jackson giúp cho chúng ta có thể chuyển đổi data dưới dạng JSON sang các định dạng data khác nhau và ngược lại. Trong bài viết này, mình hướng dẫn các bạn cách chuyển đổi data từ JSON sang CSV như thế nào các bạn nhé!

  Cách tạo REST API với JSON Server
  Ghi chú file package.json của node module

Xem thêm các việc làm JSON hấp dẫn trên TopDev

Đầu tiên, mình sẽ tạo mới một Maven project:

với Jackson Dataformat CSV dependency như sau:

<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
<version>2.13.0</version>
</dependency>

Để làm ví dụ, mình sẽ chuyển đổi chuỗi JSON sau sang tập tin CSV:

{
"name" : "Khanh",
"code" : 99,
"date" : "04-07-2017",
"gotMarried": true
}

Để bắt đầu, mình sẽ tạo mới một Application class với main() method như sau:

package com.huongdanjava.jackson;

public class Application {

public static void main(String[] args) {

}
}

Đầu tiên, các bạn có thể sử dụng phương thức readTree() của đối tượng ObjectMapper của Jackson để đọc nội dung JSON mà các bạn cần chuyển đổi. 

Có nhiều phương thức overload readTree() hỗ trợ cho các bạn làm điều này:

Các bạn có thể đọc nội dung JSON từ file, từ chuỗi, từ byte,… Tuỳ theo bài toán mà các bạn hãy sử dụng các phương thức overload của readTree() cho hợp lý nhé. Ở đây, mình sẽ lưu nội dung JSON trên vào tập tin data.json ở thư mục src/main/resources để làm ví dụ:

JsonNode jsonNode = new ObjectMapper().readTree(new File("src/main/resources/data.json"));

Nội dung JSON này sẽ được lưu vào đối tượng JsonNode như các bạn thấy!

Tiếp theo, chúng ta sẽ sử dụng đối tượng CsvSchema Builder để định nghĩa các column của tập tin CSV.

Cho ví dụ của mình thì code sẽ như sau:

CsvSchema.Builder builder = CsvSchema.builder();
jsonNode.elements().next().fieldNames().forEachRemaining(f -> builder.addColumn(f));

Đoạn code trên là chúng ta đang lấy tất cả các key trong JSON data, bao gồm name, code, date, gotMarried trong ví dụ của mình, để định nghĩa là column trong tập tin CSV các bạn nhé!

Các bạn cũng có thể chỉ định những data nào, tương ứng với key nào trong JSON data được convert qua tập tin CSV bằng cách định nghĩa CsvSchema Builder như sau:

CsvSchema.Builder builder = CsvSchema.builder()
.addColumn("name")
.addColumn("code")
.addColumn("date");

Với đoạn code này thì ví dụ của mình chỉ có data của column name, code và date được convert mà thôi. Mình sẽ sử dụng code này trong bài viết này để làm ví dụ.

Sau khi đã có CsvSchema Builder xong thì các bạn có thể lấy đối tượng CsvSchema như sau:

CsvSchema csvSchema = builder.build().withHeader();

Bây giờ thì chúng ta có thể sử dụng CsvMapper để chuyển đổi JSON data sang CSV data rồi:

CsvMapper csvMapper = new CsvMapper();
csvMapper.configure(Feature.IGNORE_UNKNOWN, true);
csvMapper.writerFor(JsonNode.class)
.with(csvSchema)
.writeValue(new File("src/main/resources/data.cvs"), jsonNode);

Bởi vì mình đang định nghĩa các column manually, nên sẽ có những column mà CsvMapper không aware được khi làm việc chuyển đổi. Do đó, mình cần cấu hình để nó ignore những column đó đi.

Trong ví dụ này, mình lưu tập tin output data.csv ở thư mục src/main/resources.

Toàn bộ code của ví dụ như sau:

package com.huongdanjava.jackson;

import com.fasterxml.jackson.core.JsonGenerator.Feature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.File;
import java.io.IOException;

public class Application {

public static void main(String[] args) throws IOException {
JsonNode jsonNode = new ObjectMapper().readTree(new File("src/main/resources/data.json"));

CsvSchema.Builder builder = CsvSchema.builder()
.addColumn("name")
.addColumn("code")
.addColumn("date");

CsvSchema csvSchema = builder.build().withHeader();

CsvMapper csvMapper = new CsvMapper();
csvMapper.configure(Feature.IGNORE_UNKNOWN, true);
csvMapper.writerFor(JsonNode.class)
.with(csvSchema)
.writeValue(new File("src/main/resources/data.csv"), jsonNode);
}
}

Kết quả khi chạy chương trình như sau:

Jackson sẽ không làm việc được với những kiểu dữ liệu nested JSON các bạn nhé.

Ví dụ như nếu các bạn có chuỗi JSON sau:

{
"name" : "Khanh",
"code" : 99,
"date" : "04-07-2017",
"gotMarried": true,
"group" : [
"ABC", "XYZ"
],
"class" : {
"name" : "A",
"code" : 123
}
}

thì khi code, các bạn cần định nghĩa manually tên các column để loại bỏ những nested JSON này ra các bạn nhé!

Bài viết gốc được đăng tải tại huongdanjava.com

Có thể bạn quan tâm:

Xem thêm việc làm CNTT hấp dẫn trên TopDev

Giới thiệu JDBC Connection Pool

jdbc connection pool
Giới thiệu JDBC Connection Pool

Bài viết được sự cho phép của tác giả Giang Phan

Thiết lập kết nối cơ sở dữ liệu là một quá trình rất tốn tài nguyên và đòi hỏi nhiều chi phí. Hơn nữa, trong một môi trường đa luồng, việc mở và đóng nhiều kết nối thường xuyên và liên tục ảnh hưởng rất nhiều đến performance và tài nguyên của ứng dụng. Trong bài này, tôi sẽ giới thiệu với các bạn Connection Pool và cách sử dụng JDBC Connection Pool trong ứng dụng Java.

Connection Pooling

Connection Pooling là gì?

Connection pool (vùng kết nối) : là kỹ thuật cho phép tạo và duy trì 1 tập các kết nối dùng chung nhằm tăng hiệu suất cho các ứng dụng bằng cách sử dụng lại các kết nối khi có yêu cầu thay vì việc tạo kết nối mới.

  Giới thiệu về Spring Session với Spring Session JDBC
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

Xem thêm nhiều việc làm Java lương cao trên TopDev

Cách làm việc của Connection pooling?

Connection Pool Manager (CPM) là trình quản lý vùng kết nối, một khi ứng dụng được chạy thì Connection pool tạo ra một vùng kết nối, trong vùng kết nối đó có các kết nối do chúng ta tạo ra sẵn. Và như vậy, một khi có một request đến thì CPM kiểm tra xem có kết nối nào đang rỗi không? Nếu có nó sẽ dùng kết nối đó còn không thì nó sẽ đợi cho đến khi có kết nối nào đó rỗi hoặc kết nối khác bị timeout. Kết nối sau khi sử dụng sẽ không đóng lại ngay mà sẽ được trả về CPM để dùng lại khi được yêu cầu trong tương lai.

Ví dụ: 

Một connection pool có tối đa 10 connection trong pool. Bây giờ user kết nối tới database (DB), hệ thống sẽ kiểm tra trong connection pool có kết nối nào đang rảnh không?

  • Trường hợp chưa có kết nối nào trong connection pool hoặc tất cả các kết nối đều bận (đang được sử dụng bởi user khác) và số lượng connection trong connection < 10 thì sẽ tạo một connection mới tới DB để kết nối tới DB đồng thời kết nối đó sẽ được đưa vào connection pool.
  • Trường hợp tất cả các kết nối đang bận và số lượng connection trong connection pool = 10 thì người dùng phải đợi cho các user dùng xong để được dùng.

Sau khi một kết nối được tạo và sử dụng xong nó sẽ không đóng lại mà sẽ duy trì trong connection pool để dùng lại cho lần sau và chỉ thực sự bị đóng khi hết thời gian timeout (lâu quá không dùng đến nữa).

Giới thiệu JDBC Connection Pool

JDBC Connection Pooling

Giới thiệu JDBC Connection Pool

Cơ chế làm việc của JDBC Connection Pooling tuân thủ theo Connection Pooling. Sau khi ứng dụng được start, một Connection Pool object được tạo, các Connection object sau này được tạo sẽ được quản lý bởi pool này.

Có nhiều thư viện hỗ trợ JDBC Conection Pooling như: C3P0Apache Commons DBCPHikariCP, … Chúng ta sẽ lần lượt tìm hiểu các cài đặt và sử dụng chúng trong phần tiếp theo của bài viết này.

Cấu hình Maven Dependencies

Tạo maven project và thêm các maven dependencies trong file pom.xml:

<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>     <groupId>com.gpcoder</groupId>     <artifactId>JdbcExample</artifactId>     <version>0.0.1-SNAPSHOT</version>     <packaging>jar</packaging>     <name>JdbcExample</name>     <url>http://maven.apache.org</url>     <properties>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <maven.compiler.source>1.8</maven.compiler.source>         <maven.compiler.target>1.8</maven.compiler.target>     </properties>     <dependencies>         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <version>8.0.17</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>1.18.10</version>         </dependency>         <!-- Connection Pool -->         <!-- 1. C3P0 -->         <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->         <dependency>             <groupId>com.mchange</groupId>             <artifactId>c3p0</artifactId>             <version>0.9.5.4</version>         </dependency>         <!-- 2. Apache Commons DBCP -->         <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->         <dependency>             <groupId>org.apache.commons</groupId>             <artifactId>commons-dbcp2</artifactId>             <version>2.7.0</version>         </dependency>         <!-- 3. HikariCP -->         <!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->         <dependency>             <groupId>com.zaxxer</groupId>             <artifactId>HikariCP</artifactId>             <version>3.4.0</version>         </dependency>     </dependencies> </project>

Lưu ý: các bạn chỉ cần sử dụng 1 trong các thư viện Conection Pooling trên, không cần phải thêm tất cả. Trong bài này mình hướng dẫn sử dụng tất cả thư viện đó nên cần thêm tất cả.

Sử dụng JDBC connection pool

Đầu tiên, cần tạo class constant chứa thông tin cấu hình kết nối database, số lượng connection tối thiểu, tối đa trong Pool.

DbConfiguration.java

package com.gpcoder.constants;

public class DbConfiguration {

public static final String HOST_NAME = "localhost";
public static final String DB_NAME = "jdbcdemo";
public static final String DB_PORT = "3306";
public static final String USER_NAME = "root";
public static final String PASSWORD = "";
public static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver";
public static final int DB_MIN_CONNECTIONS = 2;
public static final int DB_MAX_CONNECTIONS = 4;
// jdbc:mysql://hostname:port/dbname
public static final String CONNECTION_URL = "jdbc:mysql://" + HOST_NAME + ":" + DB_PORT + "/" + DB_NAME;

private DbConfiguration() {
super();
}
}

c3p0

Khởi tạo Connection Pool sử dụng C3p0 và cung cấp phương thức để get Connection. Trong class này tôi sẽ thêm một số log để các bạn theo dõi cách Connection Pool hoạt động.

C3p0DataSource.java

package com.gpcoder.pool.thirdparties;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;

import com.gpcoder.constants.DbConfiguration;
import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3p0DataSource {

private static ComboPooledDataSource cpds = new ComboPooledDataSource();

static {
try {
cpds.setDriverClass(DbConfiguration.DB_DRIVER);
cpds.setJdbcUrl(DbConfiguration.CONNECTION_URL);
cpds.setUser(DbConfiguration.USER_NAME);
cpds.setPassword(DbConfiguration.PASSWORD);
cpds.setMinPoolSize(DbConfiguration.DB_MIN_CONNECTIONS);
cpds.setInitialPoolSize(DbConfiguration.DB_MIN_CONNECTIONS);
cpds.setMaxPoolSize(DbConfiguration.DB_MAX_CONNECTIONS);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}

private C3p0DataSource() {
super();
}

public static Connection getConnection(String task) throws SQLException {
System.out.println("Getting connection for task " + task);
Connection conn = cpds.getConnection();
logPoolStatus(task);
return conn;
}

public synchronized static void logPoolStatus(String task) throws SQLException {
System.out.println("Received connection for task " + task);
System.out.println("+ Num of Connections: " + cpds.getNumConnections());
System.out.println("+ Num of Idle Connections: " + cpds.getNumIdleConnections());
System.out.println("+ Num of Busy Connections: " + cpds.getNumBusyConnections());
}
}

C3p0ConnectionPoolingExample.java

package com.gpcoder.pool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;

import com.gpcoder.pool.thirdparties.C3p0DataSource;

class C3p0WorkerThread extends Thread {

private String taskName;
private CountDownLatch latch;

public C3p0WorkerThread(CountDownLatch latch, String taskName) {
this.taskName = taskName;
this.latch = latch;
}

@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Starting. Task = " + taskName);
execute();
latch.countDown();
System.out.println(Thread.currentThread().getName() + " Finished.");
}

private void execute() {
try {
String sqlSelect = "SELECT COUNT(*) AS total FROM user";
try (Connection con = C3p0DataSource.getConnection(taskName);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sqlSelect);) {
Thread.sleep(2000);
rs.next();
System.out.println("Task = " + taskName + ": Run SQL successfully " + rs.getInt("total"));
}
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}

public class C3p0ConnectionPoolingExample {

private static final int NUMBER_OF_USERS = 8;

public static void main(String[] args) throws SQLException, InterruptedException {
final CountDownLatch latch = new CountDownLatch(NUMBER_OF_USERS);
for (int i = 1; i <= NUMBER_OF_USERS; i++) {
Thread worker = new C3p0WorkerThread(latch, "" + i);
worker.start();
}
latch.await();
System.out.println("DONE All Tasks");
C3p0DataSource.logPoolStatus("Main");
}
}

Trong chương trình trên, tôi tạo 8 Thread khác nhau truy cập data cùng một thời điểm, Connection Pool của chúng ta ban đầu khởi tạo là 2 Connection, tối đa có 4 Connection và mỗi Thread sử dụng Connection trong 2 giây.

Chạy chương trình trên, chúng ta có kết quả sau:

Thread-0 Starting. Task = 1
Thread-1 Starting. Task = 2
Thread-3 Starting. Task = 4
Thread-2 Starting. Task = 3
Thread-4 Starting. Task = 5
Thread-5 Starting. Task = 6
Thread-6 Starting. Task = 7
Thread-7 Starting. Task = 8
Getting connection for task 1
Getting connection for task 8
Getting connection for task 7
Getting connection for task 6
Getting connection for task 5
Getting connection for task 3
Getting connection for task 4
Getting connection for task 2
Received connection for task 2
+ Num of Connections: 3
+ Num of Idle Connections: 1
+ Num of Busy Connections: 2
Received connection for task 8
+ Num of Connections: 3
+ Num of Idle Connections: 0
+ Num of Busy Connections: 3
Received connection for task 1
+ Num of Connections: 3
+ Num of Idle Connections: 0
+ Num of Busy Connections: 3
Received connection for task 4
+ Num of Connections: 4
+ Num of Idle Connections: 0
+ Num of Busy Connections: 4
Task = 8: Run SQL successfully 15
Task = 4: Run SQL successfully 15
Task = 2: Run SQL successfully 15
Thread-7 Finished.
Thread-1 Finished.
Thread-3 Finished.
Received connection for task 6
+ Num of Connections: 4
+ Num of Idle Connections: 1
+ Num of Busy Connections: 3
Received connection for task 7
+ Num of Connections: 4
+ Num of Idle Connections: 0
+ Num of Busy Connections: 4
Received connection for task 5
+ Num of Connections: 4
+ Num of Idle Connections: 0
+ Num of Busy Connections: 4
Task = 1: Run SQL successfully 15
Thread-0 Finished.
Received connection for task 3
+ Num of Connections: 4
+ Num of Idle Connections: 0
+ Num of Busy Connections: 4
Task = 6: Run SQL successfully 15
Thread-5 Finished.
Task = 7: Run SQL successfully 15
Thread-6 Finished.
Task = 3: Run SQL successfully 15
Task = 5: Run SQL successfully 15
Thread-2 Finished.
Thread-4 Finished.
DONE All Tasks
Received connection for task Main
+ Num of Connections: 4
+ Num of Idle Connections: 4
+ Num of Busy Connections: 0

Như bạn thấy, tại một thười điểm chỉ có thể tối đa 4 Connection được xử lý, khi một Connection rảnh (idle) sẽ có thể xử lý tiếp một yêu cầu Connection khác. Với cách làm này, chúng ta có thể quản lý được số lượng Connection có thể mở đồng thời để phục vụ trong ứng dụng.

Apache Commons DBCP

Tương tự như C3P0, chúng ta tạo class Connection Pool như sau:

package com.gpcoder.pool.thirdparties;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbcp2.BasicDataSource;

import com.gpcoder.constants.DbConfiguration;

public class DBCPDataSource {

private static BasicDataSource ds = new BasicDataSource();

static {
ds.setDriverClassName(DbConfiguration.DB_DRIVER);
ds.setUrl(DbConfiguration.CONNECTION_URL);
ds.setUsername(DbConfiguration.USER_NAME);
ds.setPassword(DbConfiguration.PASSWORD);
ds.setMinIdle(DbConfiguration.DB_MIN_CONNECTIONS); // minimum number of idle connections in the pool
ds.setInitialSize(DbConfiguration.DB_MIN_CONNECTIONS);
ds.setMaxIdle(DbConfiguration.DB_MAX_CONNECTIONS); // maximum number of idle connections in the pool
ds.setMaxOpenPreparedStatements(100);
}

private DBCPDataSource() {
super();
}

public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}

DBCPConnectionPoolingExample.java

package com.gpcoder.pool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;

import com.gpcoder.pool.thirdparties.DBCPDataSource;

class DBCPWorkerThread extends Thread {

private CountDownLatch latch;
private String taskName;

public DBCPWorkerThread(CountDownLatch latch, String taskName) {
this.latch = latch;
this.taskName = taskName;
}

@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Starting. Task = " + taskName);
execute();
latch.countDown();
System.out.println(Thread.currentThread().getName() + " Finished.");
}

private void execute() {
try {
String sqlSelect = "SELECT COUNT(*) AS total FROM user";
try (Connection conn = DBCPDataSource.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sqlSelect);) {
Thread.sleep(2000);
rs.next();
System.out.println("Task = " + taskName + ": Run SQL successfully " + rs.getInt("total"));
}
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}

public class DBCPConnectionPoolingExample {

private static final int NUMBER_OF_USERS = 8;

public static void main(String[] args) throws SQLException, InterruptedException {
final CountDownLatch latch = new CountDownLatch(NUMBER_OF_USERS);
for (int i = 1; i <= NUMBER_OF_USERS; i++) {
Thread worker = new DBCPWorkerThread(latch, "" + i);
worker.start();
}
latch.await();
System.out.println("DONE All Tasks");
}
}

Hikari

package com.gpcoder.pool.thirdparties;

import java.sql.Connection;
import java.sql.SQLException;

import com.gpcoder.constants.DbConfiguration;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

public class HikariCPDataSource {

private static HikariConfig config = new HikariConfig();

private static HikariDataSource ds;

static {
config.setDriverClassName(DbConfiguration.DB_DRIVER);
config.setJdbcUrl(DbConfiguration.CONNECTION_URL);
config.setUsername(DbConfiguration.USER_NAME);
config.setPassword(DbConfiguration.PASSWORD);
config.setMinimumIdle(DbConfiguration.DB_MIN_CONNECTIONS);
config.setMaximumPoolSize(DbConfiguration.DB_MAX_CONNECTIONS);
// Some additional properties
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ds = new HikariDataSource(config);
}

private HikariCPDataSource() {
super();
}

public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}

HikariConnectionPoolingExample.java

package com.gpcoder.pool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;

import com.gpcoder.pool.thirdparties.HikariCPDataSource;

class HikariWorkerThread extends Thread {

private CountDownLatch latch;
private String taskName;

public HikariWorkerThread(CountDownLatch latch, String taskName) {
this.latch = latch;
this.taskName = taskName;
}

@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Starting. Task = " + taskName);
execute();
latch.countDown();
System.out.println(Thread.currentThread().getName() + " Finished.");
}

private void execute() {
try {
String sqlSelect = "SELECT COUNT(*) AS total FROM user";
try (Connection conn = HikariCPDataSource.getConnection();
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sqlSelect);) {
Thread.sleep(2000);
rs.next();
System.out.println("Task = " + taskName + ": Run SQL successfully " + rs.getInt("total"));
}
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}

public class HikariConnectionPoolingExample {

private static final int NUMBER_OF_USERS = 8;

public static void main(String[] args) throws SQLException, InterruptedException {
final CountDownLatch latch = new CountDownLatch(NUMBER_OF_USERS);
for (int i = 1; i <= NUMBER_OF_USERS; i++) {
Thread worker = new HikariWorkerThread(latch, "" + i);
worker.start();
}
latch.await();
System.out.println("DONE All Tasks");
}
}

Tự tạo Connection Pool

Nếu không muốn sử dụng thư viện có sẵn, chúng ta có thể tự tạo một Connection Pool. Tương tự như sau:

GPConnectionPool.java

package com.gpcoder.pool.custom;

import java.sql.Connection;

public interface GPConnectionPool {

Connection getConnection();

boolean releaseConnection(Connection connection);
}

GPConnectionPoolImpl.java

package com.gpcoder.pool.custom;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;

import com.gpcoder.ConnectionUtils;
import com.gpcoder.constants.DbConfiguration;

public class GPConnectionPoolImpl implements GPConnectionPool {

private static final LinkedList availableConnections = new LinkedList<>();

private int maxConnection;

public GPConnectionPoolImpl(int maxConnection) {
this.maxConnection = maxConnection;
initializeConnectionPool();
}

private synchronized void initializeConnectionPool() {
try {
while (!checkIfConnectionPoolIsFull()) {
Connection newConnection = ConnectionUtils.openConnection();
availableConnections.add(newConnection);
}
notifyAll();
} catch (SQLException e) {
e.printStackTrace();
}
}

private boolean checkIfConnectionPoolIsFull() {
return availableConnections.size() >= maxConnection;
}

@Override
public synchronized Connection getConnection() {
while(availableConnections.size() == 0) {
// Wait for an existing connection to be freed up.
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Retrieves and removes the first element of this list
return availableConnections.poll();
}

@Override
public synchronized boolean releaseConnection(Connection connection) {
try {
if (connection.isClosed()) {
initializeConnectionPool();
} else {
// Adds the specified element as the last element of this list
boolean isReleased = availableConnections.offer(connection);
// Wake up threads that are waiting for a connection
notifyAll();
return isReleased;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}

public synchronized String toString() {
StringBuilder sb = new StringBuilder()
.append("Max=" + DbConfiguration.DB_MAX_CONNECTIONS)
.append(" | Available=" + availableConnections.size())
.append(" | Busy=" + (DbConfiguration.DB_MAX_CONNECTIONS - availableConnections.size()))
;
return sb.toString();
}
}

GPDataSource.java

package com.gpcoder.pool.custom;

import java.sql.Connection;

import com.gpcoder.constants.DbConfiguration;

public class GPDataSource {

private static final GPConnectionPool gpPool = new GPConnectionPoolImpl(DbConfiguration.DB_MAX_CONNECTIONS);

private GPDataSource() {
super();
}

public static Connection getConnection() {
Connection connection = gpPool.getConnection();
System.out.println("GPPool status: " + gpPool);
return connection;
}

public static boolean releaseConnection(Connection connection) {
return gpPool.releaseConnection(connection);
}
}

GPConnectionPoolExample.java

package com.gpcoder.pool;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;

import com.gpcoder.pool.custom.GPDataSource;

class GPWorkerThread extends Thread {

private String taskName;
private CountDownLatch latch;

public GPWorkerThread(CountDownLatch latch, String taskName) {
this.taskName = taskName;
this.latch = latch;
}

@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Starting. Task = " + taskName);
execute();
latch.countDown();
System.out.println(Thread.currentThread().getName() + " Finished.");
}

private void execute() {
try {
String sqlSelect = "SELECT COUNT(*) AS total FROM user";
Connection connection = GPDataSource.getConnection();
try (Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sqlSelect);) {
Thread.sleep(2000);
rs.next();
System.out.println("Task = " + taskName + ": Run SQL successfully " + rs.getInt("total"));
}
GPDataSource.releaseConnection(connection);
} catch (SQLException | InterruptedException e) {
e.printStackTrace();
}
}
}

public class GPConnectionPoolExample {

private static final int NUMBER_OF_USERS = 8;

public static void main(String[] args) throws SQLException, InterruptedException {
final CountDownLatch latch = new CountDownLatch(NUMBER_OF_USERS);
for (int i = 1; i <= NUMBER_OF_USERS; i++) {
Thread worker = new GPWorkerThread(latch, "" + i);
worker.start();
}
latch.await();
System.out.println("DONE All Tasks");
}
}

Output chương trình:

Thread-0 Starting. Task = 1
Thread-1 Starting. Task = 2
Thread-2 Starting. Task = 3
Thread-3 Starting. Task = 4
Thread-4 Starting. Task = 5
Thread-5 Starting. Task = 6
Thread-6 Starting. Task = 7
Thread-7 Starting. Task = 8
GPPool status: Max=4 | Available=2 | Busy=2
GPPool status: Max=4 | Available=1 | Busy=3
GPPool status: Max=4 | Available=0 | Busy=4
GPPool status: Max=4 | Available=2 | Busy=2
Task = 7: Run SQL successfully 15
Task = 1: Run SQL successfully 15
Task = 8: Run SQL successfully 15
GPPool status: Max=4 | Available=0 | Busy=4
GPPool status: Max=4 | Available=0 | Busy=4
Task = 6: Run SQL successfully 15
Thread-5 Finished.
Thread-7 Finished.
GPPool status: Max=4 | Available=1 | Busy=3
Thread-6 Finished.
Thread-0 Finished.
GPPool status: Max=4 | Available=0 | Busy=4
Task = 3: Run SQL successfully 15
Task = 5: Run SQL successfully 15
Thread-2 Finished.
Thread-4 Finished.
Task = 2: Run SQL successfully 15
Task = 4: Run SQL successfully 15
Thread-1 Finished.
Thread-3 Finished.
DONE All Tasks

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm việc làm IT hấp dẫn trên TopDev

SWAP-No ROOT: Cách tạo Ram ảo cho Android không cần Root

tạo ram ảo
SWAP-No ROOT: Cách tạo Ram ảo cho Android không cần Root

Bài viết được sự cho phép của blogchiasekienthuc.com

Đang ở nhà tránh dịch chán quá các bạn ạ ! Vậy nên hôm nay mình mới đem con máy ra để “hành hạ” và viết bài thủ thuật chia sẻ cho các bạn đây.

Lần này sẽ là một ứng dụng được cho là có thể tăng được dung lượng Ram cho smartphone Android.

Nếu bạn chưa biết RAM là gì thì bạn có thể tham khảo bài viết này để hiểu hơn nhé: RAM là gì? giải thích về chức năng của RAM dễ hiểu nhất

NOTE: RAM trên máy tính hay trên điện thoại thì về cơ bản là nó hoạt động giống nhau nha các bạn !

Vậy điều này có thật sự đúng không? và liệu nó nó đạp đổ toàn bộ lý thuyết từ trước đến nay giữa quan hệ phần mềm và phần cứng hay không?

Nếu bạn muốn biết câu trả lời thì hãy đọc qua một lượt trước nhé. Okay, bắt đầu thôi nào !

  .NET core vs ASP.NET core: Phân biệt .NET Framework, .NET Core và Mono
  10 tài khoản Instagram bạn nên theo dõi để lấy ý tưởng thiết kế

Xem thêm nhiều việc làm Android lương cao trên TopDev

#1. Cách sử dụng ứng dụng SWAP – No ROOT trên Android

+ Bước 1: Ứng dụng có tên Swap – No ROOT, có thể tải về từ Play Store. Bạn có thể tìm kiếm trên kho ứng dụng, hoặc có thể truy cập trực tiếp ở đường link này !

ung-dung-nang-cap-ram-cho-android (1)

+ Bước 2: Sau đó, bạn hãy tiến hành cài đặt nó vào điện thoại của bạn. Trong quá trình cài đặt bạn hãy cấp quyền nếu được hỏi, và tiến hành tạo thêm Ram cho Android.

Giao diện sử dụng của phần mềm cực kì đơn giản như sau:

  1. Swap size cho phép bạn tùy chỉnh dung lượng Rom (bộ nhớ trong) sẽ được swap thành Ram theo đơn vị MB. Ví dụ ở dưới mình để 2000 MB, tức là gần 2GB đó các bạn.
  2. Sau khi điền dung lượng, bạn hãy chọn Creat swap để tiến hành đổi Rom thành Ram. Hoặc sau này nếu bạn không còn muốn dùng nữa, hoặc là thiếu Rom để dùng thì bạn có thể nhấn vào nút Delete swap

ung-dung-nang-cap-ram-cho-android (2)

Đơn giản vậy thôi đó 🙂 Cơ chế của ứng dụng này là giữ chỗ trước một lượng khoảng trống trên Rom để có thể chạy như Ram.

#2. Swap – No ROOT hoạt động như thế nào?

Nếu bạn đã từng làm việc với máy chủ ảo (VPS) thì thuật sữ swap đã không còn xa lạ gì nữa rồi, mỗi khi chúng ta cài đặt VPS xong thì thường tạo thêm swap cho máy ảo đó.

Mục đích của việc tạo thêm swap là để tăng lượng RAM ẢO để VPS hoạt động được ổn định hơn.

Tương tự như vậy, việc tạo thêm swap (ram ảo) cho điện thoại Android sẽ giúp cho điện thoại hoạt động được ổn định hơn mỗi khi bị full RAM vật lý.

Nguyên lý hoạt động của swap đó là: Khi hết RAM (RAM vật lý) thì hệ thống sẽ tự động sử dụng một phần ổ cứng mà bạn đã thiết lập để làm bộ nhớ cho các ứng dụng hoạt động.

Tuy là tốc độ của Ram ảo không thể so sánh với RAM vật lý được, nhưng nó sẽ giúp cho máy không bị treo và đơ, dẫn đến tình trang không sử dụng được.

#3. Swap – No ROOT có giúp nâng cấp RAM cho máy Android thật không?

Các bạn có thể nhìn ảnh dưới đây: Máy mình là Sony Xperia XZ2 với 4GB Ram, và cả trước hay sau swap, hệ thống vẫn hiển thị 4GB Ram.

Vậy nên, các bạn đừng nhầm lẫn với việc tăng RAM vật lý trong này nhé 🙂

ung-dung-nang-cap-ram-cho-android (3)

Nhưng nó cũng không phải là scam. Thật ra thì cái trò swap Ram này có từ hồi mình dùng con máy Samsung Galaxy Y rồi cơ, chắc cũng được 7 năm rồi, nó vẫn tồn tại cho tới bây giờ, và một yêu cầu bắt buộc lúc đó là phải root máy thì mới được.

Vậy tại sao ứng dụng này lại chạy được trên những máy non-root?

Vâng, là do nó dựa trên cơ chế ghi lên Rom của hệ thống Android khi Ram vậy lý quá tải như mình đã giải thích ở phần #2. Có thể các bạn đã từng vào trong phần setting để check và nhìn thấy lượng Ram trống của mình bị âm rồi đúng không?

Đó là lúc máy của bạn đang sử dụng một phần Rom để làm Ram, đúng bằng với phần bị âm kia !

Và ứng dụng này giống như là đang dọn chỗ trước cho các tác vụ yêu cầu chức năng ghi lên Rom phải khởi động vậy.

Theo như mình test, khả năng đa nhiệm của máy mình hầu như không thay đổi mấy. Tuy nhiên, với một con máy 4GB chơi Genshin Impact, cơ chế ghi lên Rom sẽ được kích hoạt sau một thời gian chơi game do Ram vật lý bị quá tải.

Thường thì mình sẽ chơi được ổn định trong vòng 30’ đầu tiên, và sau đó game sẽ lag dần, kéo theo một vài ứng dụng bị buộc đóng dưới nền để tạo lượng Ram trống cho game.

Nhưng sau khi swap thêm 2GB Ram thì thời gian chơi game ổn định tăng lên rõ rệt, và hoàn toàn không có ứng dụng nào bị buộc phải đóng dưới nền cả. Tức là app đã phát huy tác dụng !

Vậy nên, đối với những smartphone có dung lượng RAM vật lý khiên tốn thì cách tạo swap này sẽ thực sự hiệu quả, và thấy được tác dụng rõ rệt. Có lẽ app này phù hợp nhất cho máy tầm trung hoặc flagship cũ nhé các bạn.

Còn đối với những bạn đang sử dụng máy có dung lượng RAM nhiều, hoặc ít chơi game thì có lẽ cũng không cần thiết phải sử dụng. Tuy nhiên, nếu máy bạn thường xuyên có hiện tượng giật lag thì có thể thử ứng dụng này nhé !

Nam Hoàng- Bài viết gốc tại blogchiasekienthuc.com

Có thể bạn quan tâm:

Xem thêm việc làm CNTT hấp dẫn trên TopDev

Token revocation với Spring Authorization Server

token revocation
Token revocation với Spring Authorization Server

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Để revoke một access token đang còn valid, không cho Client Application sử dụng access token đó nữa, chúng ta sẽ sử dụng token revocation endpoint. Với Authorization Server được xây dựng sử dụng Spring Authorization Server, các bạn có thể sử dụng POST request sau để revoke một access token: http://localhost:8080/oauth2/revoke.

  Bean, ApplicationContext, Spring Bean Life Cycle và Component scan
  Bảo mật ứng dụng Java web bởi Spring Security

Xem thêm các chương trình tuyển dụng Spring hấp dẫn trên TopDev

Ví dụ bây giờ mình có một RegisteredClient như sau:

// @formatter:off
RegisteredClient registeredClient1 = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("huongdanjava1")
.clientSecret("{noop}123")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenSettings(tokenSettings())
.scope("accees-hello")
.build();
// @formatter:on

Lấy access token của client này, rồi gọi tới token introspection request, các bạn sẽ thấy kết quả như sau:

Bây giờ, nếu mình gọi tới request token revocation với 3 tham số trong phần body của request là token cần revoke, client_id và client_secret của access token này, các bạn sẽ thấy kết quả như sau:

Vậy là chúng ta đã revoke thành công rồi đó các bạn.

Giờ nếu các bạn gọi lại request token introspection cho access token này, các bạn sẽ thấy token invalid, như sau:

Motion Graphics Design Là Gì? Cần Kỹ Năng Gì Để Trở Thành Motion Graphics Designer?

Motion Graphics Design là gì
Motion Graphics Design là gì? Cần kỹ năng gì để trở thành Motion Graphics Designer?

Đồ họa chuyển động hay Motion Graphics Design là một làn gió mới trong thế giới sáng tạo nghệ thuật. Đặc biệt Motion Graphic Design sẽ ngày càng phổ biến hơn khi các video, phim ảnh xuất hiện nhiều hơn. Vậy Motion Graphics Design là gì? Bạn đã biết những gì về ngành nghề  này, tìm hiểu thêm với bài viết dưới đây.

Motion Graphics Design là gì?

Motion Graphics Design (hay Motion Design) có thể hiểu đơn giản nhất là nghệ thuật di chuyển một cách sáng tạo các yếu tố đồ họa. Nó có thể là những mảng khối, đường nét, chữ cái… được biến hóa bằng các phần mềm 2D làm chúng trở nên sống động và thú vị. 

Tuy nhiên, nhiều bạn có thể nhầm lẫn giữa Motion Graphics Design và Graphics Design. Điểm khác biệt nhất giữa hai thiết kế này là yếu tố chuyển động. Graphics Design là những hình ảnh đồ họa 2D/3D dưới dạng TĨNH. Trong khi đó, Motion Graphics Design là gì? Nó là những hình ảnh đồ họa 2D/3D có thể CHUYỂN ĐỘNG được.

Motion graphics design là gì
Motion graphics design là gì? Ngành nghề mới nổi được săn đón tại Việt Nam

Những loại hình motion graphics design

1. Kinetic Typography

Có thể hiểu đơn giản Kinetic Typography là “chữ động”.  Các chữ cái với các hình khối, màu sắc khác nhau được sắp xếp, trình bày lần lượt theo một cách đặc biệt tạo thành từ, thành câu, từ đó truyền tải một thông điệp hay gợi lên cảm xúc nào đó. Chính sự chuyển động nhảy múa của những con chữ khiến cho người xem có khuynh hướng bị cuốn hút, muốn đọc và khám phá ra những điều kì diệu ẩn giấu đằng sau nó.

Ngày nay, Kinetic Typography là thể loại đồ họa chuyển động độc đáo, rất được ưa chuộng và sử dụng rộng rãi từ TV commercials đến website landing pages.

Xem thêm các việc làm Designer lương cao trên TopDev

2. Explainer Video

Explainer Video là một dạng video đồ họa ngắn thường có thời lượng 1 – 3 phút. Bằng cách sử dụng hình ảnh vui nhộn kết hợp với nội dung lôi cuốn, Explainer video sẽ truyền tải một thông điệp ý nghĩa, giới thiệu hay quảng bá một doanh nghiệp nào đó đến với người xem.

Tại Việt Nam, Explainer Video là một loại hình khá mới. Nhưng, khía cạnh tuyệt vời của Explainer Videos là câu chuyện mà nó mang đến cho công chúng, một câu chuyện hay giúp thu hút khách hàng. Từ đó, Explainer Videos ngày càng chứng tỏ tầm ảnh hưởng trong vai trò quảng bá thương hiệu, giới thiệu công ty đặc biệt là Startups. 

3. Animated Infographic

Animated Infographic là hình thức trình bày các sự kiện, con số, dữ liệu một cách hấp dẫn và dễ dàng tiếp thu ngay từ những lần xem đầu tiên. Bạn sẽ không còn nhìn thấy những con số, dữ liệu nhàm chán nữa mà thay vào đó chúng sẽ được xử lý đầy màu sắc, hấp dẫn hơn.

Tuy nhiên, lưu lượng truy cập thông tin ngày càng nhiều và các Infographics cơ bản không đủ cạnh tranh để thu hút người xem. Vì thế, Animated Infographic xuất hiện cùng với những chuyển động thú vị, nhạc nền, hiệu ứng âm thanh giúp nâng trò chơi lên một tầm cao mới và dẫn dắt người xem một cách điêu luyện.

Motion graphics design – ngành nghề mới nổi được săn đón tại Việt Nam

Motion Graphics có thể truyền tải một lượng lớn thông tin mà chỉ gói gọn trong vài phút với những “chuyển động” đầy tính trực quan, lôi cuốn, giảm thiểu sự gián đoạn, vì người dùng sẽ khó rời mắt khỏi video và tò mò về chuyển động tiếp theo.

Xem thêm Tối ưu UX/UI bằng Animation – những khung hình “biết nói”

Mặt khác, hàng ngày có đến vài tỷ lượt xem video trên Facebook hay Youtube, bên cạnh đó là sự phổ biến của truyền hình, phim ảnh. Từ những nhu cầu ngày càng nhiều này mà tiềm năng Motion Graphics Design phát triển ngày càng cao nhằm nâng cấp trải nghiệm người dùng lên một tầm cao mới.

ngành hot designer
Ngành nghề mới nổi được săn đón tại Việt Nam

Khi mà hầu hết các thương hiệu, công ty đều muốn thu hút công chúng bằng những video, phim ảnh sống động thì họ cần người có thể tạo ra những điều thú vị này. Vì vậy, Motion Graphics Designer sẽ ngày càng được săn đón.

Mức lương của một Motion Graphics Designer ở Việt Nam hiện tại rơi vào khoảng tối thiểu 12 triệu/tháng và lên đến 25 triệu/tháng. Vì thế, đây được xem là ngành có mức lương cao nhất so với các nhóm ngành thiết kế khác.

Vậy, để đón đầu xu hướng và trở thành một motion designer chuyên nghiệp thì bạn cần những kỹ năng gì?

Kỹ năng cần có của motion graphics designer

Điều đầu tiên mà một Motion Designer cần đó chính là kỹ năng tư duy, kể chuyện, logic sau đó là đến khả năng tương tác với khoa học máy tính. 

kỹ năng của motion designer
Kỹ năng cần có của Motion Graphics Designer

Chi tiết hơn, các bạn cần rèn luyện cho mình những kỹ năng như:

  • Kỹ năng thiết kế đồ họa (Graphic Designer): chắc chắn rồi, vì thiết kế đồ họa chuyển động chủ yếu là mang những yếu tố đồ họa vào cuộc sống thông qua dạng hoạt hình. Việc trang bị cho bản thân kiến thức của một Graphic Designer sẽ giúp cho công việc đồ họa chuyển động của bạn dễ dàng hơn.
  • Hiểu biết về diễn hoạt trong hoạt hình (Animation): như đề cập ở trên, việc thiết kế đồ họa chuyển động là bạn mang những yếu tố 2D vào đời sống thông qua chuyển động. Vì vậy, bạn cần phải có nền tảng vững chắc về animation và các đối tượng di chuyển như thế nào để tạo ra 1 tác phẩm chuyển động hoàn chỉnh.

Xem thêm Làm sao để chuyển đổi từ Graphic Design sang UX Design?

  • Tính sáng tạo: nguồn thông tin từ khách hàng đôi khi không đủ và bạn là người biến một ý tưởng đơn giản thành những thiết kế thú vị với đầy đủ thông điệp cần truyền tải.
  • Am hiểu về màu sắc: không chỉ Motion Graphics Designer mà tất cả những ai có định hướng thiết kế đều cần hiểu biết về gam màu. Mỗi màu sắc sẽ mang lại ngữ cảnh, cảm xúc khác nhau và việc làm chủ màu sắc giúp bạn truyền tải thông điệp một cách đúng và đủ.
  • Kỹ năng công nghệ: hầu hết chúng ta đề sử dụng máy tính để thiết kế, nên bạn sẽ phải cần thích nghi là quen với các sản phẩm, tính năng mới
  • Sự độc đáo: sẽ có rất nhiều Motion Designer và để cạnh tranh hay đứng trong xu hướng ngành thì bạn cần phải tạo phong cách riêng biệt, độc đáo cho các thiết kế của mình.

Thực tế, so với các nước khác thì Việt Nam gia nhập thế giới Motion Design chậm hơn một bước. Tuy nhiên, thế hệ trẻ Việt Nam luôn có sự đam mê và khả năng sáng tạo. Gia nhập sau không có nghĩa sẽ chậm hơn so với thế giới, điều quan trọng nằm ở việc tư duy mạnh mẽ được định hướng và tiếp cận tốt. 

Intern: Nguyễn Thanh Bích Lộc

Có thể bạn quan tâm: 

Xem thêm Việc làm IT hấp dẫn trên TopDev

Hiện thực OAuth Resource Server sử dụng Spring Security OAuth2 Resource Server

oauth resource server
Hiện thực OAuth Resource Server sử dụng Spring Security OAuth2 Resource Server

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Resource Server trong OAuth2 được sử dụng để protect việc truy cập đến các resources, APIs. Nó sẽ validate access token được truyền bởi Client Application, với Authorization Server để quyết định xem liệu Client Application có quyền access tới các resources, APIs mà nó muốn hay không? Trong bài viết này, mình hướng dẫn các bạn cách hiện thực OAuth Resource Server sử dụng Spring Security OAuth2 Resource Server các bạn nhé!

  Authorization Code grant type với Proof Key for Code Exchange (PKCE) trong OAuth 2.1
  Giới thiệu về OAuth

Xem thêm các chương trình tuyển dụng Spring trên TopDev

Đầu tiên, mình sẽ tạo mới một Spring Boot project với Spring Web, Spring Security OAuth2 Resource Server để làm ví dụ:

Kết quả:

Đầu tiên, mình sẽ tạo mới một RESTful API đóng vai trò là resource mà chúng ta cần resource server protect. Nội dung của API này đơn giản như sau:

package com.huongdanjava.springsecurity;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

@GetMapping
public String hello() {
return "Hello";
}

}

Bây giờ mình sẽ tạo mới một class để cấu hình Spring Security protect cho RESTful API này với nội dung ban đầu như sau:

package com.huongdanjava.springsecurity;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.anyRequest().authenticated();
// @formatter:on
}

}

Với cấu hình ở trên, như mình đã nói trong bài viết Cấu hình Spring Security sử dụng WebSecurityConfigurerAdapter và AbstractSecurityWebApplicationInitializer, chỉ có user đã đăng nhập thì mới access được đến tất cả các request của ứng dụng và thông tin đăng nhập của user được store trong memory hoặc một database system nào đó.

Chúng ta sẽ không thể request tới http://localhost:8081/hello lúc này:

Nếu bây giờ các bạn cần implement Resource Server để authenticate tất cả các request tới ứng dụng của chúng ta sử dụng access token được issue bởi Authorization Server thì các bạn có thể thêm những dòng code sau:

package com.huongdanjava.springsecurity;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
// @formatter:on
}

}

Resource Server sẽ cần thông tin của Authorization Server để nó có thể check access token có phải do Authorization Server này issue hay không? Do đó, các bạn cần mở tập tin application.properties để cấu hình thông tin Aụthorization Server này.

Để làm ví dụ cho bài viết này, mình sẽ start Authorization Server được xây dựng sử dụng Spring Authorization Server trong bài viết này. Rồi mình sẽ cấu hình thông tin Authorization Server cho ví dụ này như sau:

server.port=8081

spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080

Mình cũng change port của ứng dụng ví dụ luôn, để khỏi bị conflict với port của Authorization Server.

Bây giờ, giả sử mình có một RegisteredClient trong Authorization Server như sau:

// @formatter:off
RegisteredClient registeredClient1 = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("huongdanjava1")
.clientSecret("{noop}123")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenSettings(tokenSettings())
.build();
// @formatter:on

Lấy access token của RegisteredClient này:

và request lại URL http://localhost:8081/hello với access token được truyền trong Authorization Bearer, các bạn sẽ thấy kết quả như sau:

Nếu các bạn để ý thì, với cách cấu hình của Spring Security ở trên thì tất cả các access token được issue bởi Authorization Server đều có thể access tới các APIs. Trong thực tế, chúng ta sẽ không làm vậy.

Trong access token có một claim là tên là scope và chúng ta sẽ dùng nó để determine là với request URL này, access token phải có scope gì thì mới access được.

Nếu các bạn decode access token của RegisteredClient ở trên, các bạn sẽ thấy, hiện tại không có claim scope nào cả:

vì chúng ta không cấu hình scope cho RegisteredClient này.

Bây giờ, mình sẽ thay đổi cấu hình của Spring Security chỉ accept request có access token có scope là “access-hello” mới truy cập được “/hello”, như sau:

package com.huongdanjava.springsecurity;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.authorizeRequests()
.antMatchers("/hello").hasAuthority("SCOPE_access-hello")
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
// @formatter:on
}

}

Chúng ta sẽ sử dụng phương thức hasAuthority() với antMachers cho request “/hello”. Tham số của phương thức hasAuthority() là một chuỗi bắt đầu với SCOPE và tiếp theo đó là tên scope mà trong access token của RegisteredClient phải có.

Lúc này, nếu restart lại ứng dụng ví dụ, và request tới “/hello” với access token của RegisteredClient ở trên, các bạn sẽ thấy lỗi 403 Forbidden như sau:

Để cấu hình thêm scope cho RegisteredClient ví dụ trên, mình sẽ sửa code như sau:

// @formatter:off
RegisteredClient registeredClient1 = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("huongdanjava1")
.clientSecret("{noop}123")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenSettings(tokenSettings())
.scope("accees-hello")
.build();
// @formatter:on

Như các bạn thấy, chúng ta sẽ sử dụng phương thức scope() để làm điều này.

Restart Authorization Server, lấy lại access token cho RegisteredClient này rồi request lại tới “http://localhost:8081/hello”, các bạn sẽ thấy kết quả “Hello ” được trả về.

Decode access token, các bạn sẽ thấy kết quả như sau:

Mức Lương Của Business Analyst Hiện Nay Bao Nhiêu?

lương của business analyst
Mức lương của Business Analyst hiện nay bao nhiêu?

Hiện nay, nghề Chuyên viên phân tích nghiệp vụ đang dần phủ rộng trên nhiều lĩnh vực, công việc chính của BA là một cầu nối giữa khách hàng với team dự án, là người chuyển giao thông tin và nắm rõ nhất về dự án mà họ đang thực hiện. Do đó, mức lương của Business Analyst được đánh giá khá cao trên thị trường việc làm. 

lương của business analyst
Mức lương của Business Analyst

Lương của Business Analyst ở một số nước phát triển trên thế giới

Dựa vào số liệu thu thập được từ trang Glassdoor, mức lương của Business Analyst trung bình năm dao động từ $40,000 – $90,000. Ngoài ra, dựa vào phân loại theo trình độ kinh nghiệm cũng sẽ ảnh hưởng đến thu nhập của các BA tại các quốc gia này. Cụ thể như sau:

Mức lương của BA ở Mỹ

Là một cường quốc về công nghệ, mức lương trung bình được ghi nhận bởi 65,561 chuyên viên phân tích nghiệp vụ ở Hoa Kỳ rơi vào khoảng $77,213/năm tương đương  $6,434/tháng. Những BA lâu năm trong nghề sẽ được trả hơn $9,000/tháng. 

business analyst
Mức lương của Business Analyst tại Mỹ (số liệu cập nhật 20/9/2021)

Mức lương của BA ở Australia

Business Analyst rất phát triển ở nước Úc, các công ty luôn dành một khoảng ngân sách lớn dành cho đội ngũ này. Mỗi nhân viên sẽ nhận được trung bình $90,000/năm tương đương $7,500/tháng. Đặc biệt, BA ở trình độ Senior sẽ được trả với hơn $10,000/tháng.

Mức lương ở một số nước châu Á

Ở châu Á, một số quốc gia công nghệ tiên tiến cũng thu hút nhiều chuyên viên BA làm việc. Chẳng hạn ở Singapore, mức lương trung bình một Junior sẽ nhận được là 3,700/tháng và $5,180/tháng cho Senior BA.  Ở Nhật Bản, trung bình lương của BA sẽ cao hơn, với $4,564/tháng cho trình độ Junior và $6,846/tháng cho trình độ Senior. 

lương châu á
Mức lương của Business Analyst ở một số nước Châu Á

Theo báo cáo của IIBA công bố năm 2017 khảo sát về mức lương của BA chỉ ra TOP 5 lĩnh vực mà chuyên viên phân tích nghiệp vụ làm việc nhiều nhất là Công nghệ thông tin, Tài chính, Chính phủ, Kinh doanh và Sức khỏe.

Xem thêm Con đường trở thành Business Analyst của Tester 

Lương của Business Analyst Việt Nam

Business Analyst đang trở thành một trong những từ khóa tìm việc phổ biến tại Việt Nam. Những năm gần đây, nhân lực theo đuổi nghề này tăng nhanh và mức lương được offer cũng thay đổi rõ rệt. Theo thống kê từ Salaryexplorer.com về mức lương của BA Việt Nam, các bạn có thể hiểu rằng cứ 100 người làm BA sẽ có:

  • 50 người có mức lương dưới 19,2 triệu đồng
  • 25 người có mức lương từ 19,2 triệu đồng đến 31,5 triệu đồng
  • 25 người có mức lương từ 13,7 triệu đồng đến dưới 19,2 triệu đồng

Mức lương trung bình của Business Analyst theo số năm kinh nghiệm tại Việt Nam được thống kê như sau: 

Mức lương của BA theo số năm kinh nghiệm tại Việt Nam (salaryexplorer.com)

Báo cáo cũng chỉ ra sự khác biệt giữa mức lương phân bổ theo giới tính của nhân lực BA tại nước ta. Cụ thể, mức lương trung bình của nam cao hơn nữ khoảng 8%.

Ngoài ra, chuyên viên phân tích nghiệp vụ có khả năng tăng lương 14% sau mỗi 16 tháng trong khi số liệu trung bình tất cả các ngành nghề tại Việt Nam dao động ở mức tăng 9% sau mỗi 17 tháng. 

Tính lương gross sang net chuẩn với công cụ tính lương của TopDev

Cơ hội nghề nghiệp của Business Analyst ở Việt Nam

Theo báo cáo thị trường IT của TopDev năm 2021, Việt Nam có 450,000 nhân lực công nghệ thông tin. Dù nước ta đang chịu ảnh hưởng bởi dịch Covid-19 nhưng một số ngành nghề vẫn duy trì được độ hot, chẳng hạn như Business Analyst. 

Hiện nay, BA xuất hiện ở nhiều lĩnh vực không chỉ riêng IT. Do đó, cơ hội nghề nghiệp khá rộng mở ở nhiều lĩnh vực. Cụ thể, chúng ta có thể trở thành một chuyên viên phân tích nghiệp vụ ở một số nhóm ngành sau:

  • Những người chuyên về lĩnh vực IT như developer, tester,… BA xuất thân từ IT thường làm trong các công ty outsource, công ty phần mềm. Các công ty thường có xu hướng tuyển những BA có nền tảng IT vì họ có thể dễ dàng triển khai project về mặt kỹ thuật và chỉ cần dành ít thời gian tìm hiểu thêm kiến thức về lĩnh vực khác. 
  • Những người chuyên về lĩnh vực khác IT như kinh tế, dịch vụ, logistic, kế toán, nhân sự, tài chính… BA không xuất thân từ kỹ thuật thường làm trong các công ty, tổ chức hay doanh nghiệp liên quan đến một lĩnh vực chuyên môn nhất định với vai trò là người tạo cầu nối giữa khách hàng và nhóm phát triển phần mềm.
  • Những người vừa có kiến thức IT, vừa nắm được kiến thức ở các lĩnh vực khác như quản lý hệ thống thông tin, quản lý quy trình phần mềm,… Người thuộc nhóm này có trình độ chuyên môn và số năm kinh nghiệm khá cao do họ đã cọ xát ở nhiều lĩnh vực khác nhau.

Một số vị trí Business Analyst phổ biến tại Việt Nam

  • Management Analyst – Chuyên viên tư vấn quản lý
  • Systems Analyst – Chuyên viên phân tích hệ thống
  • Data Analyst – Chuyên gia phân tích dữ liệu 
Một số chuyên môn chính của Business Analyst ở Việt Nam.

Các công việc BA hiện tại:

Mức lương của Business Analyst được đánh giá là khá cao so với mặt bằng chung các ngành nghề khác tại Việt Nam. Có thể thấy rằng, nghề BA đòi hỏi rất nhiều kỹ năng do đó sẽ là một thử thách không hề nhỏ dành cho những newbies mới bước chân vào nghề đồng thời cũng là cơ hội tốt để cọ xát và phát triển bản thân.

Intern: Nguyễn Ngọc Uyên

Có thể bạn quan tâm:

Xem thêm nhiều công việc CNTT hấp dẫn trên TopDev

Selenium WebDriver trên Python

selenium webdriver
Selenium WebDriver trên Python

Bài viết được sự cho phép của vntesters.com

Như các bạn thấy ở phần trước, Selenium WebDriver hỗ trợ chúng ta tuỳ biến và nâng cấp kịch bản kiểm thử ở một mức độ cao hơn Selenium IDE rất nhiều. Phần này, mình sẽ giới thiệu với các bạn cách để cấu hình và làm một kịch bản kiểm thử với Selenium WebDriver trên ngôn ngữ Python.

Xem thêm các việc làm Python lương cao trên TopDev

Cài đặt thư viện Selenium

Để cài đặt Python, các bạn có thể tham khảo ở bài “Python – Ngôn Ngữ Lập Trình”. Để sử dụng được Selenium WebDriver sau khi cài đặt Python, chúng ta cần phải cài bộ thư viện của Selenium WebDriver vào thư mục cài đặt Python. Để làm được việc này, chúng ta có nhiều cách như: Windows Install Standalone, pip install hay easy-install. Theo cá nhân mình thấy thì đi theo easy-install là dễ nhất nên dưới đây mình sẽ hướng dẫn các bạn cách này.

Thiết lập easy-install

B1. Đầu tiên, chúng ta cần có file “ez_setup.py” để có thể sử dụng được easy-install

B2. Chạy file “ez_setup.py” và đợi

  Lập trình Python trên IntelliJ IDEA (code Python trên IntelliJ)

Cài đặt Selenium WebDriver

Sau khi thiết lập được easy-install thông qua file “ez_setup.py”, trong thư mục Python\Scripts sẽ có một file “easy_install.exe” được tạo ra. Chúng ta sẽ sử dụng file này để cài đặt Selenium WebDriver cho Python.

Như tên gọi, easy-install thì hiển nhiên cách cài đặt phải là đơn giản. Chúng ta chỉ cần một bước một để hoàn thành việc cài đặt này: Chạy câu lệnh “easy_install selenium”

cai_dat_sele_1

và đợi.

cai_dat_sele_2

Vậy là chúng ta đã có thể sử dụng Selenium WebDriver với Python.

  Chạy Python web app

Thực thi kịch bản kiểm thử với Selenium WebDriver trên Python

Một file kịch bản kiểm thử với Selenium WebDriver trên Python thật ra thì nó cũng chỉ là một file .py thực thi mà thôi. Sau khi được tạo thành, chúng ta có thể thực thi file kịch bản kiểm thử như cách mà chúng ta thực thi file .py bình thường.

Để tạo ra file kịch bản kiểm thử, chúng ta có thể mở Python IDE lên và tạo mã Python. Một cách khác, chúng ta có thể Record các bước cơ bản của kịch thử và dùng Python IDE để chỉnh sửa theo ý chúng ta.

Đây là một file kịch bản kiểm thử ví dụ, mình sẽ tạo ra hai trình duyệt IE và FireFox. Trình duyệt FireFox sẽ mở trang Google và tìm “VNTesters”, trình duyệt IE sẽ mở trang Bing và tìm “VNTesters”. Cuối cùng, cả hai cùng kiểm tra một liên kết với tên “VNTesters | CHIA SẺ ĐỂ THÀNH CÔNG HƠN” được hiển thị.

Bài kế tiếp, mình sẽ đi chi tiết từng bược một của kịch bản kiểm thử ở trên để các bạn có thể nắm rõ hơn. Hẹn gặp lại.

Bài viết gốc được đăng tải tại vntesters.com

Có thể bạn quan tâm:

Xem thêm nhiều công việc CNTT hấp dẫn trên TopDev

4 cách Reset lại tường lửa (Firewall) trong Windows 10

reset firewall
4 cách Reset lại tường lửa (Firewall) trong Windows 10

Bài viết được sự cho phép của blogchiasekienthuc.com

Windows Firewall là gì thì có lẽ mình cũng không cần nói nhiều nữa, nó đã quá quen thuộc với người dùng hệ điều hành Windows rồi. Vậy đã bao giờ bạn có ý định reset lại Windows Firewall chưa?

Thông thường thì bạn sẽ không cần phải tác động hoặc thay đổi bất kỳ cài đặt nào đối với Firewall cả. Tuy nhiên, một số ứng dụng và chương trình yêu cầu chúng ta cần phải tắt tính năng bảo mật này đi thì mới có thể sử dụng được.

Hoặc cũng có thể trước đó bạn đã sử dụng Firewall để thiết lập các quy tắc cho hệ điều hành Windows, thì việc Reset lại Firewall cũng là điều khá cần thiết.

  Kiến trúc Model-View-Presenter
  10 tài khoản Instagram bạn nên theo dõi để lấy ý tưởng thiết kế

Xem thêm các việc làm IT Security hấp dẫn trên TopDev

Hoặc cũng có trường hợp Firewall (tường lửa) của hệ điều hành Windows bị xung đột với các ứng dụng khác trong quá trình cài đặt phần mềm diệt virus, hay các phần mềm điều khiển máy tính từ xa, v.v.

Mặc dù bạn có thể sửa đổi các quy tắc của tường lửa để giải quyết những xung đột này, nhưng đôi khi chúng ta thực hiện các thay đổi đối với Firewall lại tạo ra nhiều rắc rối hơn.

Vậy nên, trong bài viết này mình sẽ hướng dẫn chi tiết cho bạn một số cách Reset lại Firewall (tường lửa) trên Windows về cài đặt mặc định ban đầu nhé.

#1. Cách Reset Firewall từ Control Panel

Cài đặt lại tường lửa là việc đơn giản và bất cứ ai cũng làm được thông qua Control Panel.

+ Bước 1. Trước hết, bạn hãy mở Windows Search lên (Windows + S) => và nhập vào từ khóa control panel => sau đó nhấp vào kết quả để mở bảng điều khiển.

Hoặc một cách mở Control Panel áp dụng cho mọi hệ điều hành Windows là: Mở hộp thoại Run (Windows + R) => nhập lệnh control => và nhấn Enter.

reset-lai-tuong-lua-firewall-trong-windows-10 (1)

+ Bước 2. Ở cửa sổ tiếp theo, bạn hãy nhấp vào Network and Sharing Centre. Phần view by bạn để là Large icons nhé !

reset-lai-tuong-lua-firewall-trong-windows-10 (2)

+ Bước 3. Bây giờ bạn nhấp vào tùy chọn Windows Defender Firewall nằm ở góc trái bên dưới của cửa sổ.

reset-lai-tuong-lua-firewall-trong-windows-10 (3)

+ Bước 4. Tiếp theo, bạn chọn Restore Defaults như hình bên dưới.

reset-lai-tuong-lua-firewall-trong-windows-10 (4)

+ Bước 5. Trong cửa sổ tiếp theo, bạn nhấp vào tùy chọn Restore defaults (Khôi phục mặc định) để thực hiện Reset lại Windows Firewall nhé.

reset-lai-tuong-lua-firewall-trong-windows-10 (5)

#2. Cài đặt lại tường lửa về mặc định thông qua Windows Settings

Giống như Control Panel thôi, ứng dụng Windows Settings trên Windows 10 cũng cho phép bạn Reset Firewall một cách dễ dàng.

+ Bước 1. Trước hết, để mở Windows Settings thì bạn hãy nhấn tổ hợp phím Windows + I. Hoặc bạn nhấp vào nút Start => và chọn Settings cũng được.

reset-lai-tuong-lua-firewall-trong-windows-10 (6)

+ Bước 2. Bước tiếp theo, bạn nhấp vào tùy chọn Update & Security => sau đó bạn bạn chọn Windows Security.

reset-lai-tuong-lua-firewall-trong-windows-10 (7)

+ Bước 4. Tiếp theo, bạn nhấp vào tùy chọn Firewall & Network protection.

reset-lai-tuong-lua-firewall-trong-windows-10 (8)

+ Bước 5. Okay, bây giờ bạn chỉ cần nhấp vào tùy chọn Restore firewalls to default => sau đó nhấp vào Yes để xác nhận là được.

reset-lai-tuong-lua-firewall-trong-windows-10 (9)

#3. Reset lại tường lửa bằng lệnh trong Windows PowerShell

Nếu bạn không thích sử dụng những cách làm bên trên thì bạn có thể sử dụng các dòng lệnh để thực hiện.

+ Bước 1. Bạn nhấp chuột phải vào Start => sau đó chọn Windows PowerShell (Admin). Hoặc bạn cũng có thể sử dụng phím tắt Windows + X để mở nhanh cửa sổ này.

Ngoài ra, bạn cũng có thể nhấn Windows + S để mở Windows Search => và tìm kiếm với từ khóa powershell.

reset-lai-tuong-lua-firewall-trong-windows-10 (10)

+ Bước 2. Trong cửa sổ lệnh vừa mở, bạn nhập lệnh sau đây => và nhấn Enter là xong:

(New-Object -ComObject HNetCfg.FwPolicy2).RestoreLocalFirewallDefaults()

#4. Reset lại Firewall của Windows bằng lện trong Command Prompt

Giống như cửa sổ dòng lệnh PowerShell, bạn cũng có thể sử dụng lệnh trong Command Prompt để cài đặt lại cài đặt tường lửa.

+ Bước 1. Bạn mở CMD với quyền Admin.

reset-lai-tuong-lua-firewall-trong-windows-10 (12)

+ Bước 2. Trên cửa sổ dấu nhắc lệnh, bạn nhập lệnh sau đây => và nhấn Enter:

netsh advfirewall reset

reset-lai-tuong-lua-firewall-trong-windows-10 (13)

+ Bước 3. Cuối cùng, bạn chỉ cần khởi động lại máy tính để áp dụng cài đặt mặc định của Firewall là xong.

#5. Lời kết

Vâng, trên đây là 4 cách reset lại Firewall (tường lửa) của máy tính Windows 10 đơn giản nhất mà bạn có thể áp dụng.

Bạn cũng có thể áp dụng cho các phiên bản hệ điều hành Windows khác nữa nhé, hoàn toàn tương tự như vậy cả thôi.

Hi vọng là bài hướng dẫn này sẽ giúp ích cho bạn. Chúc các bạn thành công !

CTV: Thạch – Bài viết gốc tại blogchiasekienthuc.com

Có thể bạn quan tâm:

Xem thêm các việc làm CNTT hấp dẫn trên TopDev

Data Analyst Là Gì? Chuẩn Bị Gì Cho Hành Trình Tự Học Data Analyst?

tự học data analyst
Data Analyst Là Gì? Chuẩn Bị Gì Cho Hành Trình Tự Học Data Analyst?

Nếu bạn là người có đam mê với những con số và luôn muốn tìm hiểu ý nghĩa đằng sau các số liệu thì Data Analytics chính là ngành nghề dành cho bạn. Đây đang là ngành cực kỳ phát triển trong thời đại công nghệ số hiện tại. Hầu như ở tất cả mọi lĩnh vực đều có sự xuất hiện của Data Analyst. Vậy làm thế nào để có thể tự học Data Analyst cũng như có những cơ hội nghề nghiệp nào cho các Data Analyst tương lai? Tìm hiểu thêm cùng TopDev với bài viết dưới đây nhé!

tự học data analyst
Tự học Data Analyst cần chuẩn bị những gì?

Data Analyst là gì?

Data Analyst được biết đến là các Chuyên viên phân tích dữ liệu. Công việc chính của họ là tập trung thu thập, khai thác, chuyển đổi và xử lý bộ dữ liệu để tìm ra được vấn đề cốt lõi của nó. Từ đó có thể nắm được tình hình hoạt động cũng như tâm lý người tiêu dùng và đưa ra các đề xuất phát triển hợp lý cho các dự án của một công ty, tổ chức.

Nghe có vẻ ngắn gọn nhưng quy trình làm việc cũng như vai trò của một Data Analyst trong công ty là cực kỳ quan trọng. Theo đó, tùy vào từng công ty, từng ngành nghề cụ thể mà Data Analyst hoạt động, họ sẽ phải làm việc liên tục với báo cáo, thống kê, thu thập và quản lý cơ sở dữ liệu. Làm thế nào để các số liệu ấy được tối ưu nhất và đạt được hiệu suất cao nhất cho công ty. Do đó, để tự học Data Analyst đạt được hiệu quả, bạn cần nắm qua về những kiến thức mình cần để tâm.

Một Data Analyst cần học gì?

Để trở thành một Data Analyst giỏi về chuyên môn, việc tự học là rất quan trọng. Vậy làm thế nào để việc tự học Data Analyst đạt hiệu quả? Bạn cần lên kế hoạch học tập cụ thể với thời gian biểu riêng cho từng kiến thức khác nhau. Một số môn học bạn cần trải qua như:

data analyst cần học gì
Một số môn học cho các Data Analyst

1. Kỹ năng thống kê áp dụng

Vì công việc của một Data Analyst sẽ gắn bó với việc thu thập và phân tích số liệu, do đó có kỹ năng thống kê sẽ giúp bạn làm việc hiệu quả và dễ dàng hơn, xử lý được đầy đủ các thông tin mà không bị bỏ sót. Thêm vào đó, người có kỹ năng thống kê tốt cũng giúp người xem dễ hiểu được các vấn đề và số liệu mà Data Analyst đề cập đến trong báo cáo.

  Data Analyst là gì? Khám phá công việc của Data Analyst
  Data scientist vs data analyst: những khác biệt mà bạn cần biết

2. Các ngôn ngữ lập trình như Python, R, Matlab

Đây là các kiến thức mang tính chuyên môn cao. Nhìn chung, việc nắm bắt các ngôn ngữ lập trình R, Python, Matlab sẽ giúp các Chuyên viên phân tích dữ liệu có thể làm việc theo một quy trình khoa học dữ liệu. Các ngôn ngữ này đều có một kho thư viện lớn của bên thứ ba cho phép và cung cấp đầy đủ các chức năng cho việc phân tích dữ liệu.

3. Công cụ truy vấn cơ sở dữ liệu như SQL

SQL là một công cụ tập hợp các lệnh để tương tác với cơ sở dữ liệu. Với ngôn ngữ SQL, Data Analyst có thể dùng nó để lưu trữ và truy xuất dữ liệu trong cơ sở dữ liệu có liên quan một cách dễ dàng. Hiện nay, SQL là ngôn ngữ chuẩn và được sử dụng ở hầu hết tất cả các cơ sở dữ liệu quan hệ.

Xem thêm Business Analyst Cần Học Gì Để Trở Thành Chuyên Gia Trong Ngành?

Ngoài ra, còn có một số kiến thức chuyên ngành khác mà các Data Analyst tương lai không nên bỏ qua như:

  • Tìm hiểu các công cụ thống kê như Minitab, Microsoft Excel
  • Hệ thống phân tích thống kê SAS
  • Khai phá dữ liệu (Data Mining)
  • Trực quan hóa dữ liệu (Data Visualization)
  • Xác suất (Probability)

Lộ trình phát triển nghề nghiệp của các Data Analyst

Bắt đầu với vị trí Data Analyst, nếu làm tốt và đủ đam mê với công việc, bạn có thể phát triển lên nhiều vị trí khác như:

  • Data Scientist DS (Chuyên gia khoa học dữ liệu)

Về cơ bản, đây là vị trí cao hơn và phát triển dựa trên vai trò của một Data Analyst. Các công việc bạn phải đảm nhiệm cũng sẽ liên quan đến việc thu thập các dữ liệu cần thiết và thiết kế thuật toán dựa trên số liệu đó, từ đó đưa ra các phương án phát triển phù hợp.

phát triển data analyst
Cơ hội nghề nghiệp của Data Analyst
  • Data Engineer DE

Với vai trò là một kỹ sư, bạn sẽ chuyên về xử lý dữ liệu thông qua việc thu thập dữ liệu từ nhiều nguồn khác nhau để xử lý chúng thành các dữ liệu có thể dùng được ngay tại kho dữ liệu trung tâm. Đây là vị trí đòi hỏi chuyên môn khá cao về mặt kỹ thuật và công nghệ.

  • Chief Data Officer (CDO)

Đây là vị trí bạn đạt được như thành quả cho sự cố gắng không ngừng nghỉ của mình với vai trò từ một Data Analyst. CDO sẽ nắm quyền quản lý toàn bộ các dữ liệu trong công ty cũng như phân bố hoạt động hợp lí để tiếp tục phát triển nguồn cơ sở dữ liệu của công ty.

Như nhiều vị trí khác liên quan đến kỹ thuật, chuyên viên phân tích dữ liệu cũng cần sự kiên trì và nhẫn nại trong suốt quá trình tự học Data Analyst. Nỗ lực bền bỉ sẽ được đền đáp xứng đáng. Hi vọng các thông tin được cung cấp sẽ giúp bạn dễ dàng hơn trong hành trình chinh phục ước mơ của mình. Đón đọc thêm nhiều bài viết hấp dẫn khác cùng TopDev/blog nhé!

Có thể bạn quan tâm:

Xem thêm công việc IT hấp dẫn trên TopDev

Tổng quan về JPA (Java Persistence API)

jpa
Tổng quan về JPA (Java Persistence API)

Bài viết được sự cho phép của tác giả Giang Phan

Bất kỳ một ứng dụng nào cũng đều cần phải thực hiện các tháo tác (CRUD) đến database bằng việc lưu trữ, truy vấn dữ liệu. Chúng ta cần phải viết nhiều code để thực hiện các việc này.

Với công nghệ JDBC trước đây, chúng ta phải thực hiện các việc: mở kết nối vào Database, tạo các Statement, ResultSet, … và sau cùng phải đóng tất cả các thứ đó lại. Dẫn đến code sẽ trở nên cồng kềnh, khó mở rộng và bảo trì. Chúng ta cũng cần phải làm việc với cả Java code và SQL. Thực tế, từng Database khác nhau thì câu SQL có một số phần khác nhau, nên đòi hỏi chúng ta phải nắm được sự khác biệt này để viết code cho phù hợp. Khi ứng dụng muốn chuyển từ database sang database khác (ví dụ từ MySQL sang Oracle) thì chắc chắn sẽ có một số phần của câu SQL cần phải đổi. Công việc sửa code lại đòi hỏi phải test lại ứng dụng. Điều này sẽ tốn thời gian, chi phí phát triển và cũng gặp không ít rủi ro. Để khắc phục nhược điểm này, đã có rất nhiều Framework ra đời với mục đích giúp xóa đi vấn để về tương thích giữa các Database, giúp tập trung vào phần xử lý nghiệp vụ.

Trong phần tiếp theo của bài viết này, tôi sẽ giới thiệu với các bạn JPA (Java Persistence API) – một chuẩn đặc tả cho các ORM Framework giải quyết vấn đề trên.

  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java
  10 tips để trở thành Java Developer xịn hơn

Xem thêm các việc làm Java lương cao trên TopDev

Giới thiệu JPA

JPA là gì?

JPA là viết tắt của Java Persistence API, nó là một đặc tả Java cho việc ánh xạ giữa các đối tượng Java với cơ sở dữ liệu quan hệ sử dụng công nghệ phổ biến là ORM (Object Relational Mapping).

JPA cung cấp đầy đủ các công cụ cho phép chúng ta có thể thao tác với cơ sở dữ liệu một cách đơn giản và nhanh chóng. JPA có thể dùng để persist một đối tượng Java (POJO – Plain Old Java Object) vào trong cơ sở dữ liệu hoặc lấy dữ liệu từ cơ sở dữ liệu và ánh xạ (mapping) ra các đối tượng Java một cách đơn giản.

JPA hoạt động như một cầu nối giữa các table/ các mối quan hệ giữa các table trong database và các class/ mối quan hệ giữa các object. Ví dụ: table USER với các column (Id, username, password) sẽ tương ứng với class User.java với các field Id, username, password. Từ đó mỗi khi truy vấn table hay các column ta sẽ gọi trực tiếp các phương thức trên các class, các field của class mà không cần quan tâm tới việc đang dùng loại database nào, kiểu dữ liệu database ra sao, …

ORM là gì?

ORM là viết tắt của Object Relational Mapping, là một công nghệ/ khái niệm/ quá trình chuyển đổi dữ liệu từ ngôn ngữ hướng đối tượng sang Database quan hệ và ngược lại. Ví dụ, trong Java nó được thực hiện với sự trợ giúp của Reflection và JDBC.

ORM có khả năng xử lý các thao tác của nhiều loại cơ sở dữ liệu khác nhau một cách dễ dàng mà không quan tâm đến loại database sử dụng (SQL Server, MySQL, PostgreSQL, …) hay loại thao tác sử dụng (INSERT, UPDATE, DELETE, SELECT, …).

Một số ORM framework hỗ trợ JPA

JPA chỉ là một API định nghĩa các đặc tả cần thiết và không có code hiện thực từ những đặc tả đó. Nó chỉ chứa những hướng dẫn để hiện thực ORM. Do đó cần phải có một cài đặt ORM để hoạt động và persist các đối tượng Java. Các ORM Framework có thể sử dụng cho JPA như: Hibernate, iBatis, Eclipse Link, OpenJPA, ….

Lợi ích của JPA

  • Đơn giản hóa công nghệ cho tầng persistence (tầng dữ liệu).
  • Không phụ thuộc vào các framework ORM.
  • Có nhiều nhà cung cấp hỗ trợ cài đặt JPA.
  • Dữ liệu có thể được lưu trữ thông qua việc ORM.

Tại sao nên dùng JPA

  • Viết ít code hơn.
  • Performance tốt.
  • Độc lập về database.
  • Không phải làm việc với SQL.
  • Hỗ trợ cấu hình triển khai bằng annotation và xml.
  • Có nhiều framework ORM miễn phí hỗ trợ có thể dùng để phát triển nhiều loại ứng dụng khác nhau.
  • JPA là một đặc tả đã được chuẩn hóa và là một thành phần trong đặc tả EJB 3.
  • Dễ dàng chuyển từ một ORM này sang một ORM khác. Ví dụ từ iBatis sang Hibernate.

Kiến trúc JPA

JPA sử dụng metadata để ánh xạ các đối tượng persistence với các bảng trong cơ sở dữ liệu. JPA hỗ trợ SQL như là một ngôn ngữ truy vấn để dễ dàng xử lý các truy vấn cơ sở dữ liệu. Ngôn ngữ truy vấn JPA có thể dùng thực thi cả truy vấn tĩnh và truy vấn động.

JPA bao gồm ba thành phần chính là: EntityEntityManager, và EntityManagerFactory. Ngoài ra còn có, EntityTransaction, Persistence, Query.

Entity

Entity là các đối tượng thể hiện tương ứng 1 table trong cơ sở dữ liệu. Entity thường là các class POJO đơn giản, chỉ gồm các phương thức getter, setter.

Dưới đây là một số đặc điểm của một Entity:

  • Entity có thể tương tác với cơ sở dữ liệu quan hệ.
  • Entity được xác định thông qua một định danh (id), tương đương với khóa chính trong table của cơ sở dữ liệu quan hệ.
  • Entity hỗ trợ transaction.
  • Entity hỗ trợ kế thừa giống như những class Java khác.

EntityManager

EntityManager là một interface cung cấp các API cho việc tương tác với các Entity.

Một số chức năng cơ bản của EntityManager như:

  • Persist: phương thức này dùng để lưu một thực thể mới tạo vào cơ sở dữ liệu.
  • Merge: dùng để cập nhật trạng thái của entity vào cơ sở dữ liệu.
  • Remove: xóa một instance của entity.

EntityManagerFactory

EntityManagerFactory được dùng để tạo ra một instance của EntityManager.

Persistence

Một Persistence định nghĩa một tập hợp các Entity class được quản lý bởi 1 instacne của EntityManager trong ứng dụng.

Persistence (javax.persistence.Persistence) class bao gồm các phương thức static để lấy instance của EntityManagerFactory.

EntityTransaction

Một Transaction là một tập hợp các thao tác trong đó tất cả các thao tác phải được thực hiện thành công hoặc tất cả thất bại.

Một database transaction bao gồm một tập hợp các câu lệnh SQL được committed hoặc rolled back trong một unit.

EntityTransaction có quan hệ 1-1 với EntityManager. Bất kỳ thao tác nào được bắt đầu thông qua đối tượng EntityManager đều được đặt trong một Transaction. Đối tượng EntityManager giúp tạo EntityTransaction.

Query

Đây là một interface, được mỗi nhà cung cấp JPA implement để có được các đối tượng quan hệ đáp ứng các tiêu chí (criteria) truy vấn.

Hình bên dưới mô tả quan hệ giữa các thành phần trên:

Các tính năng của JPA

Một số tính năng của JPA:

  • JPA hỗ trợ plugable, tức là có thể sử dụng nhiều 3rd khác nhau như Hibernate hay MyBatis.
  • Hỗ trợ cấu hình thông qua annotation và xml.
  • Giảm bớt số lớp yêu cầu cho việc phát triển persistence.
  • Không cần phải viết các mô tả triển khai trong XML. Các Annotation dựa trên metadata đã hỗ trợ trong các ứng dụng JPA.
  • Đã chuẩn hóa ORM và dễ dàng phát triển hơn.
  • JPA hỗ trợ truy vấn động và tĩnh.
  • Nhiều IDE hỗ trợ phát triển ứng dụng JPA và có thể tự động sinh code ánh xạ từ cơ sở dữ liệu thành các entity và ngược lại.

Trong bài này tôi chỉ giới thiệu với các bạn các khái niệm cơ bản về JPA và kiến trúc của nó. Trong các bài viết tiếp theo chúng ta sẽ cùng tìm hiểu về Hibernate – một implement của JPA, được sử dụng rất nhiều trong các ứng dụng.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm nhiều công việc CNTT hấp dẫn trên TopDev

Authentication trong Spring Security

authentication
Authentication trong Spring Security

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Trong bài viết Tổng quan về quy trình xử lý request trong Spring Security, mình đã giới thiệu sơ qua với các bạn về các thành phần chính trong một flow cho phần authentication của Spring Security framework. Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết hơn về cách Spring Security handle phần authentication như thế nào các bạn nhé!

  Bean, ApplicationContext, Spring Bean Life Cycle và Component scan
  API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth

Xem thêm các chương trình tuyển dụng Spring trên TopDev

Đầu tiên, mình sẽ tạo mới một Spring Boot project với Spring Security Starter and Spring Web Starter để làm ví dụ.

Kết quả như sau:

Như mình đã nói trong bài viết Tổng quan về quy trình xử lý request trong Spring Security, class AuthenticationManager sẽ là class đảm nhận việc authentication trong Spring Security:

Request sau khi đi qua AuthenticationFilter, thông tin đăng nhập của user sẽ được convert sang đối tượng Authentication với implementation là class UsernamePasswordAuthenticationToken. AuthenticationManager sẽ sử dụng thông tin trong class UsernamePasswordAuthenticationToken để làm authentication.

Mặc định thì Spring hỗ trợ chúng ta authenticate username, password sử dụng class DaoAuthenticationProvider.

Khi authenticate, với thông tin authentication trong class UsernamePasswordAuthenticationToken, Spring Security sẽ lấy thông tin username trong UsernamePasswordAuthenticationToken để kiểm tra trong UserCache đã có thông tin của username này chưa? Không hiểu sao code hiện tại sử dụng cho UserCache lại là:

private UserCache userCache = new NullUserCache();

NullUserCache thì chỉ return null thông tin UserDetails thôi các bạn!

Vì không có thông tin trong cache, nên Spring Security sẽ sử dụng đối tượng của interface UserDetailsService để lấy thông tin UserDetails sử dụng username.

Interface UserDetailsService chỉ có duy nhất 1 abstract method là loadUserByUsername():

public interface UserDetailsService {

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

Implement của interface UserDetailsService được sử dụng trong trường hợp này là InMemoryUserDetailsManager vì mình ko sử dụng database cho ví dụ trong bài viết này.

Nếu có thông tin user với username mà chúng ta đang gửi lên lúc nhấn nút Login, đối tượng UserDetails chứa thông tin của user đó sẽ được return về.

Ở đây Spring Security còn làm thêm vài thao tác check user nữa trước khi check thông tin password của user: bao gồm check user có bị lock không, user có đang enable không và user có bị expired không?

Class DefaultPreAuthenticationChecks implement interface UserDetailsChecker được sử dụng để làm điều này với phương thức check().

Spring Security sẽ check thông tin password mà user truyền, có giống với thông tin trong hệ thống không? Sử dụng phương thức additionalAuthenticationChecks().

Ở đây, thông tin password sẽ tuỳ vào encoder mà chúng ta đang configure với Spring Security thì class Encoder tương ứng sẽ được sử dụng trong quá trình check password.

Sau khi đã check thông tin password xong, Spring Security sẽ có bước kiểm tra xem password có bị expired không sử dụng class DefaultPostAuthenticationChecks với phương thức check().

Trong quá trình handle authentication flow, nếu bất cứ exception gì xảy ra, thì interface AuthenticationFailureHandler với implementation SimpleUrlAuthenticationFailureHandler sẽ handle exception này.

Còn nếu mọi thứ diễn ra trơn tru, không có lỗi gì cả thì interface AuthenticationSuccessHandler với implementation là class SavedRequestAwareAuthenticationSuccessHandler sẽ handle..

Chi tiết cho những điều đã xảy ra ở trên, các bạn có thể đọc thêm code của class AbstractAuthenticationProcessingFilter phương thức private doFilter():

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
try {
Authentication authenticationResult = attemptAuthentication(request, response);
if (authenticationResult == null) {
// return immediately as subclass has indicated that it hasn't completed
return;
}
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
// Authentication success
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authenticationResult);
}
catch (InternalAuthenticationServiceException failed) {
this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
unsuccessfulAuthentication(request, response, failed);
}
catch (AuthenticationException ex) {
// Authentication failed
unsuccessfulAuthentication(request, response, ex);
}
}

class UsernamePasswordAuthenticationFilter với phương thức attemptAuthentication():

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
username = (username != null) ? username : "";
username = username.trim();
String password = obtainPassword(request);
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}

và phương thức authenticate() trong class AbstractUserDetailsAuthenticationProvider:

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
() -> this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.onlySupports",
"Only UsernamePasswordAuthenticationToken is supported"));
String username = determineUsername(authentication);
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
if (user == null) {
cacheWasUsed = false;
try {
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
}
catch (UsernameNotFoundException ex) {
this.logger.debug("Failed to find user '" + username + "'");
if (!this.hideUserNotFoundExceptions) {
throw ex;
}
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
}
try {
this.preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
}
catch (AuthenticationException ex) {
if (!cacheWasUsed) {
throw ex;
}
// There was a problem, so try again after checking
// we're using latest data (i.e. not from the cache)
cacheWasUsed = false;
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
this.preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
}
this.postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (this.forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication, user);
}

các bạn nhé!

Các bạn có thể chạy debug, add breakpoint vào những phương thức này, để hiểu thêm về cách Spring Security đang xử lý cho phần authentication nha các bạn.

Sau khi hiểu chi tiết xong thì các bạn có thể add custom authentication filter như mình đã làm trong bài viết Custom authentication filter đăng nhập không cần password trong Spring Security dễ dàng, tuỳ theo mục đích của các bạn!

Bài viết gốc được đăng tải tại huongdanjava.com

Có thể bạn quan tâm:

Xem thêm nhiều công việc IT hấp dẫn trên TopDev

MMA Việt Nam Sẽ Công Bố 4 Báo Cáo Thị Trường Quan Trọng Tại MMA IMPACT VIETNAM 2021

MMA

Cụ thể, tại sự kiện MMA Impact Vietnam Virtual diễn ra trong hai ngày 7&8 tháng 10, MMA Việt Nam cùng Ban điều hành sẽ công bố 4 Báo cáo quan trọng được mong đợi nhất năm. Bao gồm: Báo cáo về hệ sinh thái Modern Marketing; Báo cáo về thị trường tiếp thị số nông thôn; Báo cáo về hệ sinh thái Martech tại Việt Nam; Báo cáo về tổng quan Mobile Marketing do đối tác toàn cầu Warc thực hiện cùng MMA APAC.

Đăng ký tham gia ngay tại đây. 

MMA Impact Vietnam Virtual 2021 được đánh giá là sự kiện lớn nhất về tiếp thị hiện đại năm 2021. Sự kiện được tổ chức bởi MMA Việt Nam sẽ thu hút hơn 5000 người tham dự khắp Châu Á. MMA Impact Vietnam Virtual 2021 quy tụ hơn 50 nhà lãnh đạo, họ là Tổng giám đốc, Chủ tịch các Tập đoàn; Giám đốc Marketing, Giám đốc khu vực… từ các doanh nghiệp lớn trong và ngoài nước. 

Một trong những nội dung được mong chờ nhất tại sự kiện chính là 4 báo cáo về toàn cảnh thị trường Modern Marketing và xu hướng phát triển của tiếp thị hiện đại, được trình bày bởi các thành viên trong Ban điều hành MMA Việt Nam.

Báo cáo 1: Báo cáo về hệ sinh thái Modern Marketing (Tiếp thị hiện đại)

Báo cáo về hệ sinh thái Modern Marketing (The ecosystem landscape of modern marketing 2021) là báo cáo đầu tiên được công bố, được trình bày bởi bà Tammy Phan – Giám đốc Marketing của Google Việt Nam và anh Nghĩa Nguyễn – Giám đốc Kiến thức tại GroupM Việt Nam, mang đến các thông tin tổng quát về tình hình phát triển của hệ sinh thái Modern Marketing tại Việt Nam trong bối cảnh Covid-19 thay đổi nhiều cục diện thị trường. 

Theo đó, Việt Nam là thị trường tăng trưởng nhanh nhất khu vực Đông Nam Á, nguyên nhân chủ yếu đến từ sự gia tăng thu nhập của người dân, sự thay đổi trong lối sống và hành vi mua sắm. Hệ quả là, xu hướng tiêu dùng cũng như các cơ hội kinh doanh tại Việt Nam có sự biến chuyển nhanh chóng với nhiều tín hiệu tích cực, thể hiện rõ trong các con số về quy mô kinh tế cũng như chỉ số thu nhập. 

Cùng với đó, báo cáo cũng chỉ ra thách thức cho các thương hiệu khi công nghệ đang dần chiếm lĩnh đời sống và chi phối thói quen của người tiêu dùng. Sự lên ngôi của các công nghệ mới như AI (Trí tuệ nhân tạo), Machine Learning, các hoạt động đo lường… khiến người làm tiếp thị ngày càng đối diện với nhiều thử thách. 

Báo cáo sẽ giúp người nghe hiểu được toàn cảnh thị trường cũng như các xu hướng tiếp thị tại Việt Nam hiện tại. Hiểu rõ thị trường chính là bước đầu tiên để các doanh nghiệp thành công khi bắt đầu ý tưởng, sản phẩm kinh doanh mới. 

Báo cáo 2: Báo cáo về hệ sinh thái MarTech tại Việt Nam 

Báo cáo này (The Current state of MarTech in Vietnam and What’s Next?) do chính Đồng chủ tịch MMA Việt Nam, thành viên Ban Điều Hành và đại diện là bà Nguyễn Thị Mai, Phó Chủ Tịch Marketing, Homecare của Unilever trình bày. Báo cáo chỉ ra sự phát triển của hệ sinh thái MarTech tại thị trường Việt Nam – được hiểu và một loạt phần mềm và công cụ hỗ trợ cho mục tiêu tiếp thị. Khi công nghệ phát triển, sự phức tạp trong hành vi và hành trình tiêu dùng, khiến cho nhà tiếp thị cần trang bị một bộ công cụ hỗ trợ giúp tối ưu hoá nỗ lực của mình trên bất kỳ kênh truyền thông nào. 

Trong bối cảnh Covid-19 gây ra nhiều thay đổi trong nhu cầu và hành vi mua sắm, MarTech đã có sự thay đổi/ phát triển ra sao để có thể hỗ trợ và phát triển hoạt động kinh doanh cho doanh nghiệp? Những thương hiệu, nhãn hàng nào đang thành công trong việc ứng dụng hoạt động MarTech? Tất cả sẽ được giải đáp trong báo cáo này. 

Báo cáo 3: Báo cáo về thị trường tiếp thị số nông thôn

Dưới tác động của chuyển đổi số, người tiêu dùng tại Việt Nam ngày càng thích ứng tốt với công nghệ và các thiết bị điện tử. Đến cuối năm 2020, lần đầu tiên số lượng người dùng Internet các khu vực ngoài đô thị (ven đô và nông thôn) lên đến 91%, vượt qua TV cả về mức độ thâm nhập và thời gian sử dụng. Điều này chứng tỏ tác động đáng kinh ngạc của thiết bị di động và công nghệ đến nhóm người dùng này, đặc biệt trong bối cảnh Covid-19 tác động đến hành vi mua sắm và tiêu thụ thông tin. 

Báo cáo về thị trường tiếp thị số nông thôn (Beyond Metros, the leapfrogging to Mobile-first economy & New Growth Paths) do bà Nguyễn Giáng Xuân – Giám đốc Truyền thông và Kinh doanh Toàn cầu hóa Facebook Việt Nam cùng với GroupM Việt Nam trình bày sẽ cung cấp thông tin rõ hơn về xu hướng này. 

Báo cáo 4: Báo cáo về Tổng quan Mobile Marketing do đối tác toàn cầu Warc thực hiện cùng MMA APAC.

Báo cáo này do MMA APAC cùng phối hợp thực hiện với Warc, đối tác toàn cầu hàng năm. Đây là báo cáo quan trọng cung cấp các chỉ số tiếp thị liên quan đến Mobile Marketing tại Việt Nam cũng như Khu vực APAC. Người nghe sẽ nắm bắt tất cả thông tin về attribution của mobile marketing, ngân sách đầu tư mobile marketing cũng như các chỉ số quan trọng mà các nhà tiếp thị quan tâm cùng với dự đoán sự phát triển của hệ sinh thái này trong các năm tiếp theo. 

Báo  cáo sẽ được Bà AMY RODGERS, Tổng biên tập mảng Research & Rankings, WARC trình bày tại ngày đầu tiên của sự kiện.

4 báo cáo này hứa hẹn sẽ mang đến bức tranh toàn cảnh về tiếp thị hiện đại cho các nhà tiếp thị, agency, nhà quản lý và các nhân sự trong ngành, gợi mở những chỉ dẫn mang tính chiến lược cho người làm nghề đồng thời thể hiện uy tín và giá trị của MMA tại Việt Nam – đơn vị có 10 năm đồng hành cùng sự phát triển của thị trường tiếp thị nội địa. 

Sự kiện dành vé tặng miễn phí cho các vị trí C-level từ tất cả doanh nghiệp có mối quan tâm và đang ứng dụng tiếp thị hiện đại trong việc tiếp cận và quản trị khách hàng đến từ nhiều lĩnh vực khác nhau.

———–

Thông tin về MMA:

MMA là hiệp hội tiếp thị di động thương mại phi lợi nhuận hàng đầu thế giới, bao gồm hơn 800 công ty thành viên, đến từ gần 50 quốc gia. Các thành viên của MMA tại Việt Nam đến từ mọi mảng trong hệ sinh thái tiếp thị di động, bao gồm brands marketer, agency, nền tảng công nghệ, công ty truyền thông… với các tên tuổi như Facebook, Google, GroupM, Coca-Cola, Unilever…

Sứ mệnh của MMA là đẩy nhanh quá trình chuyển giao và đổi mới của marketing thông qua thiết bị di động, thúc đẩy tăng trưởng kinh doanh với sự tương tác mạnh mẽ hơn của người tiêu dùng. 

Để biết thêm thông tin về MMA, vui lòng truy cập www.mmaglobal.com    

Làm thế nào để TẮT ĐỘ TRỄ KHỞI ĐỘNG trên Windows?

tắt khởi động trễ
Làm thế nào để TẮT ĐỘ TRỄ KHỞI ĐỘNG trên Windows?

Bài viết được sự cho phép của blogchiasekienthuc.com

Khi hệ điều hành Windows khởi động, theo mặc định thì nó sẽ đợi khoảng 10s trước khi khởi chạy các chương trình khởi động cùng Win và các phần mềm mà bạn vừa mở.

“Độ trễ” này giúp cho các dịch vụ hệ thống của Windows hoạt động hoàn toàn rồi mới đến lượt các phần mềm khởi động cùng Windows, giúp cho máy tính chạy trơn tru hơn một chút, không bị giật lag, Full Disk ổ cứng… khi bạn mới mở máy tính.

Tuy nhiên, nếu muốn thì bạn hoàn toàn có thể tắt “thời gian trễ” này đi. Bởi vì hầu như chúng ta sẽ mở app/ phần mềm ngay sau khi khởi động máy tính. Việc tắt “thời gian trễ” này sẽ giúp ứng dụng được mở nhanh hơn, không tốn thời gian của chúng ta.

  10 điều bạn có thể làm với Linux mà bạn không thể làm với Windows
  6 cách mở Services Management Console trên Windows 10

Xem thêm việc làm Windows Phone lương cao trên TopDev

Lưu ý: Cách này chỉ nên dùng cho các máy tính có sử dụng ổ cứng SSD mà thôi và phải có cấu hình đủ mạnh (core i5 thế hệ mới 10, 11 trở lên). Còn các máy tính dùng ổ cứng HDD thì không khuyến khích nha các bạn.

#1. Chỉnh sửa thông qua Registry Editer

Registry là một công cụ rất có ích. Tuy nhiên nếu bạn nhầm lẫn trong việc chỉnh sửa thì khả năng máy tính của bạn bị lỗi rất cao. Chính vì vậy hãy backup lại registry trước khi làm nha.

+ Bước 1: Đầu tiên, bạn nhấn tổ hợp phím Windows + R để mở hộp thoại Run => sau đó nhập regedit => và bấm OK.

cach-tat-do-tre-khoi-dong-tren-windows-10 (1)

+ Bước 2: Sau đó, hộp thoại Registry Editor sẽ xuất hiện, bây giờ bạn hãy truy cập theo đường dẫn sau:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer

cach-tat-do-tre-khoi-dong-tren-windows-10 (2)

+ Bước 3: Tiếp theo, bạn bấm chuột phải vào key Explorer => sau đó bấm New => chọn Key như hình bên dưới.

cach-tat-do-tre-khoi-dong-tren-windows-10 (3)

+ Bước 4: Bạn nhập tên key là Serialize.

cach-tat-do-tre-khoi-dong-tren-windows-10 (4)

+ Bước 5: Tiếp theo, ở bên phải cửa sổ, bạn bấm chuột phải và bấm New => và chọn DWORD (32-bit) Value.

cach-tat-do-tre-khoi-dong-tren-windows-10 (5)

+ Bước 6: Tiếp theo, bạn đặt tên/ đổi tên key thành StartupDelayInMSec. Sau đó bấm đúp chuột vào key đó và set giá trị thành 0 => rồi bấm OK.

cach-tat-do-tre-khoi-dong-tren-windows-10 (6)

OK, vậy là xong rồi đó. Cuối cùng bạn khởi động lại máy tính để áp dụng. Nếu bạn muốn bật lại tính năng delay này thì bạn chỉ việc xóa key này là được nhé.

#2. Tải file vô hiệu hóa tính năng Delay khi khởi động Windows (khuyên dùng)

Ok, nếu các bạn thấy các bước ở bên trên quá lằng nhằng và phức tạp, hoặc sợ bị lỗi máy tính thì các bạn có thể tải file mà mình làm sẵn dưới đây:

  • Link tải: Tại đây hoặc tại đây !
  • Mật khẩu: blogchiasekienthuc.com
  • SHA1: BB7B6FF66CC086B40AAA11D72C7ADB2D36FFA826

Sau khi giải nén thì sẽ có hai file sau đây:

  1. File DisableStartupDelay là để tắt độ trễ khởi đông Windows.
  2. Còn file EnableStartupDelay để bật lại độ trễ khởi động Windows.

cach-tat-do-tre-khoi-dong-tren-windows-10 (7)

Để sử dụng thì rất đơn giản thôi, bấm đúp chuột vào file bạn muốn sử dụng, lúc này sẽ có một cảnh báo là Regedit sẽ thay đổi, bạn bấm Yes để tiếp tục hoặc No để hủy bỏ.

cach-tat-do-tre-khoi-dong-tren-windows-10 (8)

Sau khi bấm Yes thì sẽ xuất hiện thông báo thành công như sau. Bạn bấm OK để kết thúc.

cach-tat-do-tre-khoi-dong-tren-windows-10 (9)

Vậy là xong rồi, giờ thì bạn có thể khởi động lại máy tính để áp dụng các thay đổi.

#3. Lời kết

Vâng, như vậy mình đã hướng dẫn xong cho các bạn cách để bật hoặc tắt độ trễ khi khởi động trên hệ điều hành Windows rồi nhé.

Chúc các bạn thành công và hãy linh hoạt sử dụng để phù hợp với máy tính của bạn nhé. Đừng quên vote 5 sao cho bài viết nếu bạn thấy hữu ích với bạn nha 🙂

Hoàng Tuấn – Bài viết gốc tại blogchiasekienthuc.com

Có thể bạn quan tâm:

Xem thêm các việc làm CNTT hấp dẫn trên TopDev

Khắc phục lỗi Confluence trên Server CentOS 7

lỗi confluence
Khắc phục lỗi Confluence trên Server CentOS 7

Bài viết được sự cho phép của tác giả Lê Chí Dũng

Khi sử dụng Confluence trên server riêng đôi khi bị lỗi vì cài đặt các package ảnh hưởng đến folder cài đặt chẳng hạn. Khi server bị lỗi việc kết nối gián đoạn thường thấy thông báo ERR_CONNECTION_TIMED_OUT.

  Cài đặt ConfigServer Security and Firewall (CSF) và Webmin trên CentOS 7
  App User Centricity: Làm sao tăng tỷ lệ duy trì lên 66%?

Xem thêm nhiều việc làm ERP hấp dẫn trên TopDev

Để xử lý tình trạng này mình đưa ra 1 số giải pháp khắc phục như sau:

  1. Stop Confluence rồi sau đó start lại. Nếu cách này vẫn không khắc phục được thì làm cách thứ 2.
    cd /opt/atlassian/confluence/bin/
    # Stop 
    ./stop-confluence.sh
    
    # Start
    ./start-confluence.sh
  2. Restart lại server. Nếu cách này vẫn không khắc phục được thì làm cách thứ 3. Chắc chắn sẽ được.
  3. Nếu có backup dữ liệu hằng ngày, thì Uninstall  gói cài đặt Confluence sau đó Install lại. Sau đó Restore lại dữ liệu đã được backup.
    Uninstall Confluence bằng cách vào folder đã cài đặt confluence chạy lệnh Uninstall

    cd /opt/atlassian/confluence/
    ./Uninstall

    Sau khi Uninstall, restart lại server và install lại và restore dữ liệu lại.
    https://confluence.atlassian.com/doc/installing-confluence-on-linux-143556824.html

Bài viết gốc được đăng tải tại lcdung.top

Có thể bạn quan tâm:

Xem thêm nhiều công việc IT hấp dẫn trên TopDev

Tạo ứng dụng Jakarta EE MVC sử dụng Maven trong Eclipse

jakarta ee mvc

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Trong bài viết này, mình sẽ hướng dẫn các bạn tạo mới một ứng dụng Jakarta EE MVC với Maven trong Eclipse các bạn nhé!

  Build executable jar sử dụng Maven Shade Plugin
  Hiện thực một Maven Archetype

Xem thêm các việc làm Django lương cao trên TopDev

Đầu tiên, trong Eclipse, các bạn hãy vào File, chọn New rồi chọn Maven project:

Tạo ứng dụng web sử dụng Maven trong Eclipse

Để tạo một project Jakarta EE MVC với Maven, cách nhanh nhất là chúng ta sẽ sử dụng một cho Maven Archetype dành cho Jakarta EE MVC project. Mình có tạo mới một Maven Archetype để làm điều này, tên là huongdanjava-jakartaee8-archetype, sử dụng implementation cho Jakarta EE MVC 1.1.0 từ Eclipse Krazo. Các bạn có thể sử dụng nhé!

Ở cửa sổ trên, chúng ta sẽ không chọn Create a simple project (skip archetype selection), để mặc định rồi nhấn nút Next nha các bạn.

Đây là cửa sổ cho phép chúng ta lựa chọn Maven Archetype. Các bạn có thể filter và sử dụng huongdanjava-jakartaee8-archetype như sau:

Nhấn nút Next nha các bạn:

Tạo ứng dụng web sử dụng Maven trong Eclipse

Đây là cửa sổ cho phép chúng ta thay đổi các giá trị của Maven Group Id, Maven Artifact Id, Version và cả tên package nữa đó các bạn.

Mình sẽ điền các giá trị này như sau:

Nhấn nút Finish để hoàn thành nhé các bạn.

Kết quả:

Đến đây thì chúng ta có thể sử dụng một trong các Server Runtime hỗ trợ Jakarta EE để chạy ứng dụng của chúng ta rồi. Các bạn có thể sử dụng GrassFish để làm điều này.

Kết quả:

Bài viết gốc được đăng tải tại huongdanjava.com
Có thể bạn quan tâm:
Xem thêm chương trình tuyển dụng việc làm IT hấp dẫn trên TopDev

Làm việc với Redis sử dụng Redisson

redis
Làm việc với Redis sử dụng Redisson

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

Redisson là một thư viện Java client cho Redis. Sử dụng nó, các bạn có thể thao tác, thêm xoá, sửa data và nhiều thao tác khác nữa với Redis server. Trong bài viết này, mình sẽ hướng dẫn các bạn những thao tác cơ bản với Redis sử dụng Redisson các bạn nhé!

  15 ví dụ sử dụng map, reduce và filter
  Cài đặt Redis sử dụng Docker

Xem thêm các chương trình tuyển dụng Redux trên TopDev

Đầu tiên, mình sẽ tạo mới một Maven project

với Redisson dependency để làm ví dụ:

<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.3</version>
</dependency>

Nhớ start Redis server lên các bạn nhé! Có thể tham khảo cách cài đặt Redis server sử dụng Docker tại đây.

Class RedissonExample có nội dung ban đầu như sau:

package com.huongdanjava.redis;

public class RedissonExample {

public static void main(String[] args) {

}
}

Chúng ta sẽ sử dụng đối tượng RedissonClient để làm việc với Redis server và phương thức static create() của class Redisson sẽ giúp chúng ta tạo mới đối tượng RedissonClient này.

Mặc định nếu Redis server chạy ở local, các bạn có thể sử dụng phương thức static create() không có tham số để connect tới Redis server:

RedissonClient redissonClient = Redisson.create();

còn nếu các bạn đang cần connect tới một remote Redis server thì chúng ta cần cấu hình thông tin của remote server đó. Chúng ta sẽ sử dụng class Config để làm điều này.

Redisson hỗ trợ chúng ta connect tới Redis server theo nhiều cách deployment khác nhau, ví dụ như:

  • Single node
  • Master with slave nodes
  • Sentinel nodes
  • Clustered nodes
  • Replicated nodes

Các bạn có thể chọn cách kết nối sử dụng đối tượng Config như sau:

Trong ví dụ của bài viết này, mình sẽ sử dụng single server với cấu hình như sau:

package com.huongdanjava.redis;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {

public static void main(String[] args) {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://localhost:6379")
.setConnectionPoolSize(10)
.setConnectionMinimumIdleSize(5)
.setConnectTimeout(30000);

RedissonClient redissonClient = Redisson.create(config);
}
}

Như các bạn thấy, ở đây mình cũng có thêm một số configuration liên quan đến connection bao gồm connection pool, connection idle và cả connection timeout (ms nha các bạn). Đây là những cấu hình cần thiết để chúng ta không phải đóng mở connection tới Redis server nhiều lần đó các bạn!

Bây giờ thì các bạn có thể thao tác với Redis server sử dụng đối tượng RedissonClient này rồi.

Ví dụ, các bạn có thể lưu giá trị rồi retrieve giá trị này bằng key như sau:

redissonClient.getBucket("test").set("khanh");
System.out.println(redissonClient.getBucket("test").get());

Chúng ta gọi phương thức getBucket() để tạo mới hoặc lấy về thông tin cần set giá trị. Phương thức getBucket() sẽ trả về cho chúng ta một đối tượng RBucket, đối tượng này có thể nắm giữ một đối tượng bất kỳ, sau đó thì chúng ta sẽ dùng phương thức set() của đối tượng RBucket này để set giá trị hoặc update giá trị cho nó!

Kết quả như sau:
Các bạn cũng có thể lưu thông tin một đối tượng Map và retrieve đối tượng Map này bằng key như sau:

package com.huongdanjava.redis;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {

public static void main(String[] args) {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://localhost:6379")
.setConnectionPoolSize(10)
.setConnectionMinimumIdleSize(5)
.setConnectTimeout(30000);

RedissonClient redissonClient = Redisson.create(config);

redissonClient.getMap("testMap").put("a", 1);
redissonClient.getMap("testMap").put("b", 2);
redissonClient.getMap("testMap").put("c", 3);

System.out.println(redissonClient.getMap("testMap").keySet().toString());
System.out.println(redissonClient.getMap("testMap").values().toString());
}
}

Phương thức getMap() sẽ trả về đối tượng RMap, giúp chúng ta có thể thêm, update hoặc retrieve cặp key với value của nó.

Kết quả:

Redis cũng hỗ trợ chúng ta lưu giá trị chỉ trong một khoảng thời gian nào đó mà thôi.

Để làm được điều này, đối với đối tượng Map, các bạn có thể sử dụng phương thức getMapCache() như sau:

package com.huongdanjava.redis;

import java.util.concurrent.TimeUnit;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {

public static void main(String[] args) throws InterruptedException {
Config config = new Config();
config.useSingleServer()
.setAddress("redis://localhost:6379")
.setConnectionPoolSize(10)
.setConnectionMinimumIdleSize(5)
.setConnectTimeout(30000);

RedissonClient redissonClient = Redisson.create(config);

redissonClient.getMapCache("testMapCache").put("a", 1, 2, TimeUnit.SECONDS);

System.out.println(redissonClient.getMapCache("testMapCache").keySet().toString());

Thread.sleep(3000);

System.out.println("After 2s: " + redissonClient.getMapCache("testMapCache").keySet());
}
}

Kết quả:

Như các bạn thấy, sau 2s, dữ liệu trong Map đã bị expired.

Còn rất nhiều thao tác với Redis mà các bạn có thể làm với Redisson nữa. Tuỳ theo nhu cầu, các bạn hãy research thêm nhé!

Bài viết gốc được đăng tải tại huongdanjava.com

Có thể bạn quan tâm:

Xem thêm nhiều công việc IT hấp dẫn trên TopDev

Ứng dụng của Currying Function

currying function
Ứng dụng của Currying Function

Bài viết được sự cho phép của tác giả Lưu Bình An

Currying function là một kỹ thuật viết function, thay vì nhận nhiều tham số cùng lúc, thành nhiều function nhỏ, trên từng function nhỏ cho ta truyền vào tuần tự các tham số

Có thể đọc lại bài này của mình

const add = (a, b) => a + b
console.log(add(1,2))

// viết thành currying
const add = a => b => a + b
console.log(add(1)(2))

Câu hỏi là tại sao mình lại viết như thế này ta?

Ví dụ chúng ta có một mảng

const list = [
  { id: 1, name: 'Steve', email: 'steve@example.com' },
  { id: 3, name: 'Pamela', email: 'pam@example.com' },
  { id: 4, name: 'Liz', email: 'liz@example.com' }
]

Chúng ta muốn xóa phần tử có name=John

const noJohn = list.filter(item => item.name !== 'John')

Tưởng tượng chúng ta có function filter kiểu như vậy ở nhiều nơi trong code, để đảm bảo DRY, chúng ta sẽ viết riêng một function

  Ứng dụng của Currying Function
  1001 Tips: Con trỏ và hàm (Pointer & Function) trong C++

Xem thêm nhiều việc làm Javascript mới trên TopDev

const filtering = item => item.name !== name

const filterByName = (list, name) => list.filter(filtering)

Tuy nhiên lỗi nè, const filtering = item => item.name !== name làm sao biết được name? Currying đến giải cứu đây

// curring
const filtering = (name) => (item) => item.name !== name

const filterByName = (list, name) =>
	list.filter(filtering(name))

Chuyện gì đã xảy ra? Có thể viết lại tường minh hơn để chúng ta dễ hình dung, không dùng arrow function

function filterByName(list, name) {
    return list.filter(function(nameToFilter) {
        return function(item) {
            return item.name !== nameToFilter
        }
    // truyền `name` giống như thời jQuery
    }(name))
}

Phiên bản Currying đỉnh của chóp

const filter = predicate => array => array.filter(predicate)
const filterBy = propertyName => propertyValue => filter(item[propertyName] => propertyValue)

// sử dụng
const filterByName = filterBy('name')
const filterByNameJohn = filterByName("John")

console.log(filterByNameJohn(list))

A practical example of how to use Currying in Javascript

Bài viết gốc được đăng tải tại vuilaptrinh.com

Có thể bạn quan tâm:

Xem thêm Việc làm CNTT hấp dẫn trên TopDev

Business Analyst Cần Học Gì Để Trở Thành Chuyên Gia Trong Ngành?

business analyst cần học gì
Business Analyst Cần Học Gì Để Trở Thành Chuyên Gia Trong Nghề?

Trong những năm trở lại đây, Business Analyst đã trở thành một ngành nghề cực hot với những ai đam mê số liệu, được xem là “linh hồn” của nhiều lĩnh vực khác nhau. Nhiều bạn trẻ hứng thú với công việc này và mong muốn tìm kiếm cho mình một cơ hội để trải nghiệm. Vậy bắt đầu từ đâu để có thể trở thành một Business Analyst? Một Business Analyst cần học gì và rèn luyện như thế nào để trở nên thành thục với công việc? Cùng TopDev tìm hiểu thêm những vấn đề này với bài viết dưới đây nhé!

business analyst cần học gì
Business Analyst là gì? Nên học gì để trở thành Business Analyst?

Business Analyst là gì?

Business Analyst còn được viết tắt là BA, có thể hiểu là một Chuyên viên phân tích nghiệp vụ. Theo đó, công việc hàng ngày của một BA sẽ hoạt động theo quy trình gồm thu thập, phân tích và giải quyết các vấn đề phát sinh cho một doanh nghiệp, tổ chức. Công việc họ phụ trách chính là làm thế nào để có thể giải quyết được các yêu cầu mà khách hàng đưa ra cũng như dựa vào số liệu để giúp doanh nghiệp đề ra những phương án phát triển. Trong suốt quá trình đó, BA sẽ làm việc với các bên liên quan như developers, nhân viên QC,… để phối hợp giải quyết vấn đề.

Có một số quan điểm lầm tưởng rằng Business Analyst cũng chính là những người làm về lập trình hay là dân IT. Tuy nhiên, hiện nay, không chỉ trong ngành công nghệ thông tin mà hầu như ở tất cả mọi ngành nghề đều có sự xuất hiện của Chuyên viên phân tích nghiệp vụ. Từ ngân hàng, thương mại điện tử, tài chính,… đều có các nhân viên BA làm việc. Do đó, có thể hiểu một cách đơn giản rằng nhân viên BA sẽ làm việc với các nhân viên IT, hoặc cũng có thể họ đã có kinh nghiệm về IT để giải quyết vấn đề chứ không hoàn toàn là một người chuyên về lập trình.

Xem thêm các việc làm Business Analyst hấp dẫn trên TopDev

Business Analyst cần học gì để thành công?

Chưa có một chuyên ngành hay trường học nào ở Việt Nam đào tạo chuyên sâu 100% về ngành học này. Tuy nhiên, để trở thành một nhân BA, bạn có thể lựa chọn một số ngành học liên quan như:

business-analyst-hoc-cntt
Các ngành học dành cho dân Business Analyst tương lai

1. Ngành Công nghệ thông tin

Không phải ngẫu nhiên mà những người làm trong ngành IT thường được xem là dân BA, vì đa phần dân IT là những người dễ dàng nhất trong việc chuyển đổi sang làm trong lĩnh vực phân tích nghiệp vụ. Theo đó, bạn có thể lựa chọn rất nhiều ngành học khác nhau trong ngành công nghệ thông tin để phát triển đam mê của mình:

  • Khoa học máy tính
  • An toàn thông tin
  • Truyền thông và an ninh mạng
  • Kỹ thuật lập trình
  • Kỹ thuật phần mềm

Các ngành học này sẽ mang đến cho người học một cái nhìn cơ bản về ngành công nghệ thông tin nói chung và kỹ thuật chuyên ngành nói riêng. Bên cạnh đó, đây cũng là nhóm ngành đòi hỏi suy nghĩ logic rất cao, do đó, bạn có thể học được cách xây dựng, vận hành, phát triển các hệ thống phần mềm một cách hiệu quả nhất. Những bài tập thực tế cần giải quyết trong quá trình học cũng giúp ích rất nhiều cho công việc của một BA sau này.

>>> Xem thêm: Mức Lương Của Business Analyst Hiện Nay Bao Nhiêu?

2. Ngành Kinh tế

Trong nhóm ngành kinh tế, các ngành học bạn có thể lựa chọn như quản trị kinh doanh, quản trị tài chính, kế toán, kiểm toán, ngân hàng,… Các công việc của Chuyên viên phân tích dữ liệu liên quan rất nhiều đến các yếu tố tài chính, lợi nhuận công ty, khách hàng. Vậy nên, những sinh viên tốt nghiệp ngành kinh tế được xem là những “mầm non” đầy hứa hẹn cho vị trí Business Analyst.

business analyst
Công việc của business analyst

Để có thể làm tốt nhất công việc của một BA cũng như giúp giữ lửa đam mê khi làm trong ngành, trong quá trình học kinh tế bạn cũng có thể đăng kí thêm một số khóa học ngắn hạn về công nghệ thông tin. Đây chắc chắn sẽ là điểm cộng cực lớn cho việc phân tích dữ liệu và làm việc sau này của bạn.

  Nghề Tester Và Những Triển Vọng Trong Tương Lai
  Data Analyst là gì? Khám phá công việc của Data Analyst

3. Ngành hệ thống thông tin và quản lý

Đây được xem là nhóm ngành đào tạo sát nhất với nghề BA. Các lựa chọn chính của ngành hệ thống thông tin và quản lý gồm Kiến thức cơ bản về Kinh tế và Kiến thức cơ bản đến chuyên sâu của Hệ thống thông tin quản lý. Các môn học này đi sâu vào đào tạo cho sinh viên khả năng tổng hợp và xử lý dữ liệu. Kỹ năng quản lý hệ thống thông tin là cực kỳ cần thiết với bất kỳ doanh nghiệp nào trong việc tổ chức và điều hành hoạt động của công ty.

Business Analyst là một công việc hấp dẫn cả về nhân lực và thu nhập trong thời điểm hiện tại. Mức lương của nhân viên BA được đánh giá khá cao so với mặt bằng chung. Do đó, yêu cầu chuyên môn với vị trí này cũng rất lớn. Để làm tốt hơn, không còn cách nào khác, bạn phải rèn luyện và không ngừng học hỏi. Đón đọc thêm nhiều bài viết hấp dẫn khác tại TopDev/blog nhé!

Có thể bạn quan tâm:

Xem thêm các công việc IT hấp dẫn trên TopDev

Cài đặt và sử dụng Hibernate

hibernate
Cài đặt và sử dụng Hibernate

Bài viết được sự cho phép của tác giả Giang Phan

Trong các bài viết trước chúng ta đã cùng tìm hiểu các khái niệm về JPA và Hibernate. Trong bài này, chúng ta sẽ cùng tìm hiểu cách cài đặt và sử dụng Hibernate.

Để sử dụng Hibernate, chúng ta sẽ lần lượt thực hiện các bước sau:

  • Tạo maven project.
  • Khai báo thư viện Hibernate và thư viện JDBC ứng với loại database cần sử dụng.
  • Tạo các Entity và các mapping.
  • Tạo file cấu hình Hibernate.
  • Tạo đối tượng SessionFactory
  • Sử dụng SessionFactory để thực hiện các câu lệnh truy vấn đến database.
  Hibernate Batch processing
  Hibernate Interceptor & StatementInspector

Xem thêm nhiều việc làm Data Engineer lương cao trên TopDev

Cài đặt Hibernate

Tạo maven project và trong file pom.xml khai báo thư viện Hibernate 5, và thư viện JDBC tương ứng cho các loại Database khác nhau MySQL, PostgreSQL, Oracle, SQL Server, …

Trong bài này, tôi sẽ sử dụng database MySQL. Nội dung file pom.xml như sau:

<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>     <groupId>com.gpcoder</groupId>     <artifactId>HibernateTutorial</artifactId>     <version>0.0.1-SNAPSHOT</version>     <packaging>jar</packaging>     <name>HibernateTutorial</name>     <url>http://maven.apache.org</url>     <properties>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <maven.compiler.source>1.8</maven.compiler.source>         <maven.compiler.target>1.8</maven.compiler.target>     </properties>     <dependencies>         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>1.18.10</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->         <dependency>             <groupId>org.hibernate</groupId>             <artifactId>hibernate-core</artifactId>             <version>5.4.7.Final</version>         </dependency>         <!-- MySQL -->         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->         <dependency>             <groupId>mysql</groupId>             <artifactId>mysql-connector-java</artifactId>             <version>8.0.17</version>         </dependency>         <!-- Unit Test -->         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>3.8.1</version>             <scope>test</scope>         </dependency>     </dependencies> </project>

Tạo các Entity và các mapping

Tiếp theo chúng ta sẽ tạo các Enity. Mỗi Entity sẽ đại diện cho một bảng trong database.

Giả sử tôi có một table user với cấu trúc như sau:

CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`fullname` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`modified_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Chúng ta sẽ sử dụng các Annotation để ánh xạ (mapping) class và property trong Java tương ứng với các table và column trong database.

User.java

package com.gpcoder.entities;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Data
@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String fullname;

@Column
private String username;

@Column
private String password;

@Column(name = "created_at")
private Date createdAt;

@Column(name = "modified_at")
private Date modifiedAt;
}

Một số Annotation được sử dụng:

  • @Entity : cho biết đây là một Entity.
  • @Table : cho biết đây là một Table trong database, chúng ta có thể chỉ định tên tương ứng và các ràng buộc trong database. Mặc định, Hibernate sẽ lấy tên class tương ứng với tên table trong database nếu nó không được chỉ định name.
  • @Id : đây là Identity của Entity. nó tương đương với khóa chính (Primary key) của table.
  • @GeneratedValue : được sử dụng để Hibernate tự động tạo ra giá trị và gán vào cho một cột trong trường hợp insert mới một Entity vào database.
  • @Column : được sử dụng để chú thích đây là một column trong database. Nó có thể bao gồm các thông tin ràng buộc của column như độ dài của cột, cho phép null hay không, … Mặc định, Hibernate sẽ lấy tên property tương ứng với tên column trong database nếu nó không được chỉ định name.

Chúng ta sẽ tìm hiểu chi tiết về các Annotation của Hibernate ở một bài viết khác.

Tạo file cấu hình Hibernate

Để làm việc với Hibernate, chúng ta cần phải có một file cấu hình. Trong file này, chúng ta sẽ khai báo loại database mà chúng ta sẽ sử dụng, những thông tin cần thiết để Hibernate có thể kết nối đến database đó và những Java object mà chúng ta đã ánh xạ từ java object (entity) với các table trong database.

Tạo file hibernate.cfg.xml  và đặt nó trong thư mục src\main\resources

Nội dung file này như sau:

<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration>     <session-factory>         <!-- Database setting -->         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>         <property name="connection.url">jdbc:mysql://localhost:3306/gp_system?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf8</property>         <property name="connection.username">root</property>         <property name="connection.password"></property>                   <!-- JDBC connection pool (use the built-in) -->         <property name="connection.pool_size">4</property>         <!-- SQL dialect -->         <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>         <!-- Enable Hibernate's automatic session context management -->         <property name="current_session_context_class">thread</property>         <!-- Disable the second-level cache -->         <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>         <!-- Show all executed SQL to console -->         <property name="show_sql">true</property>         <!-- Entity mapping -->         <mapping class="com.gpcoder.entities.User" />               </session-factory> </hibernate-configuration>

Tạo đối tượng SessionFactory

Như đã giới thiệu ở bài viết trước, SessionFactory là một interface giúp tạo ra session kết nối đến database bằng cách đọc các cấu hình trong Hibernate configuration.

SessionFactory là đối tượng nặng (heavy weight object) và được sử dụng thường xuyên nên chúng ta sẽ tạo một class singleton HibernateUtils để sử dụng sau này.

HibernateUtils.java

package com.gpcoder.utils;

import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtils {

private static final SessionFactory sessionFactory = buildSessionFactory();

private HibernateUtils() {
super();
}

private static SessionFactory buildSessionFactory() {
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() //
.configure() // Load hibernate.cfg.xml from resource folder by default
.build();
Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
return metadata.getSessionFactoryBuilder().build();
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

public static void close() {
getSessionFactory().close();
}
}

Sử dụng SessionFactory để thực hiện các câu lệnh truy vấn đến database

Chúng ta đã chuẩn bị đầy đủ mọi thứ, công việc bây giờ là sử dụng thôi.

Đầu tiên, chúng ta cần mở một session để làm việc với Hibernate:

Session session = HibernateUtils.getSessionFactory().openSession();

Để bắt đầu làm việc, chúng ta sẽ mở một Transaction mới:

session.beginTransaction();

Truy vấn database: Hibernate hỗ trợ nhiều cách để truy vấn database, trong bài này chúng ta sẽ sử dụng HQL để truy vấn database. HQL có một chút khác biệt với SQL:

  • SQL: Truy vấn dữ liệu trên các table và column.
  • HQL: Truy vấn dữ liệu trên các entity và property.

Sau khi đã sử dụng xong, chúng ta cần gọi commit() để lưu mọi thay đổi xuống database.

session.getTransaction().commit();

Ví dụ bên dưới sẽ thực hiện các thao tác: Insert, Update, Delete, Count, Select dữ liệu của database.

package com.gpcoder;

import java.util.Date;
import java.util.List;

import org.hibernate.Session;

import com.gpcoder.entities.User;
import com.gpcoder.utils.HibernateUtils;

public class HibernateExample1 {

public static void main(String[] args) {

try (Session session = HibernateUtils.getSessionFactory().openSession();) {
// Begin a unit of work
session.beginTransaction();

// Insert user
Date currentDate = new Date();
User user1 = new User();
user1.setFullname("Hibernate Example");
user1.setUsername("gpcoder");
user1.setPassword("123456"); // Should encode password
user1.setCreatedAt(currentDate);
user1.setModifiedAt(currentDate);
Long userId = (Long) session.save(user1);
System.out.println("User id = " + userId);

// Count user from database
Long numberOfUser = session.createQuery("SELECT COUNT(id) FROM User", Long.class).uniqueResult();
System.out.println("Number of user in database: " + numberOfUser);

// Get user by id
User savedUser = session.find(User.class, userId);
System.out.println("savedUser: " + savedUser);

// Update user
savedUser.setFullname("GP Coder");
session.update(savedUser);

// Get users
List users = session.createQuery("FROM User", User.class).list();
users.forEach(System.out::println);

// Delete user
session.delete(savedUser);

// Count user from database
numberOfUser = session.createQuery("SELECT COUNT(id) FROM User", Long.class).uniqueResult();
System.out.println("Number of user in database: " + numberOfUser);

// Commit the current resource transaction, writing any unflushed changes to the database.
session.getTransaction().commit();
}
}
}

Một số phương thức được sử dụng:

  • save() : insert một entity vào database. Phương thức này trả về id của record đã được save.
  • update() : cập nhật entity vào database.
  • delete() : xóa entity khỏi database.
  • createQuery() : tạo câu lệnh query đến database.
  • find() : tìm entity dựa vào id được cung cấp.

Chạy chương trình trên, chúng ta có kết quả như sau:

Hibernate: insert into user (created_at, fullname, modified_at, password, username) values (?, ?, ?, ?, ?)
User id = 1
Hibernate: select count(user0_.id) as col_0_0_ from user user0_
Number of user in database: 1
savedUser: User(id=1, fullname=Hibernate Example, username=gpcoder, password=123456, createdAt=Sat Oct 26 00:04:47 ICT 2019, modifiedAt=Sat Oct 26 00:04:47 ICT 2019)
Hibernate: update user set created_at=?, fullname=?, modified_at=?, password=?, username=? where id=?
Hibernate: select user0_.id as id1_0_, user0_.created_at as created_2_0_, user0_.fullname as fullname3_0_, user0_.modified_at as modified4_0_, user0_.password as password5_0_, user0_.username as username6_0_ from user user0_
User(id=1, fullname=GP Coder, username=gpcoder, password=123456, createdAt=Sat Oct 26 00:04:47 ICT 2019, modifiedAt=Sat Oct 26 00:04:47 ICT 2019)
Hibernate: delete from user where id=?
Hibernate: select count(user0_.id) as col_0_0_ from user user0_
Number of user in database: 0

Như các bạn thấy, sử dụng Hibernate việc truy vấn database đơn giản hơn rất nhiều so với sử dụng JDBC API.

Tài liệu tham khảo:

Bài viết gốc được đăng tải tại gpcoder.com

Có thể bạn quan tâm:

Xem thêm công việc ngành IT hấp dẫn trên TopDev