Skip to content

Commit

Permalink
Merge branch 'main' into js
Browse files Browse the repository at this point in the history
  • Loading branch information
nimonian authored Sep 6, 2024
2 parents e63408e + c262c12 commit 8bdafbb
Show file tree
Hide file tree
Showing 31 changed files with 1,565 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .cbfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[languages]
js = ["prettier"]
java = ["google-java-format -"]
1 change: 1 addition & 0 deletions .vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default defineConfig({
'/bash/': sidebars.bash,
'/express/': sidebars.express,
'/git/': sidebars.git,
'/javalin/': sidebars.javalin,
'/html-css/': sidebars.htmlCss,
'/java/': sidebars.java,
'/js/': sidebars.javascript,
Expand Down
1 change: 1 addition & 0 deletions .vitepress/sidebars/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { bash } from './bash.js'
export { express } from './express.js'
export { git } from './git.js'
export { javalin } from './javalin.js'
export { htmlCss } from './html-css.js'
export { javascript } from './javascript.js'
export { java } from './java.js'
Expand Down
76 changes: 76 additions & 0 deletions .vitepress/sidebars/java.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,81 @@ export const java = [
},
{ text: 'Data types', link: '/java/data-types' }
]
},
{
text: 'Data and iteration',
collapsed: true,
items: [
{
text: 'Arrays',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
},
{
text: 'Strings',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
},
{
text: 'Loops',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
},

{
text: 'Objects',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
}
]
},

{
text: 'Object oriented programming',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' },
{
text: 'Design patterns',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
}
]
},

{
text: 'Testing',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
},

{
text: 'Building projects',
collapsed: true,
items: [
{ text: 'Creating a Maven project', link: '/java/qq' },
{ text: 'Making a CLI', link: '/java/qq' },
{ text: 'Handling Errors', link: '/java/qq' },
]
},

{
text: 'Asynchronous code',
collapsed: true,
items: [
{ text: 'qq', link: '/java/qq' }
]
}
]
49 changes: 49 additions & 0 deletions .vitepress/sidebars/javalin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export const javalin = [
{ text: 'Introduction', link: '/javalin/index' },
{
text: 'Data layer',
items: [
{
text: 'Managing the database',
link: '/javalin/managing-the-database'
},
{
text: 'Connecting to a database',
link: '/javalin/connecting-to-a-database'
},
{
text: 'Adding a model layer',
link: '/javalin/adding-a-model-layer'
}
]
},
{
text: 'Creating an API',
items: [
{ text: 'Creating a server', link: '/javalin/creating-a-server' },
{ text: 'Routing and Controllers', link: '/javalin/routing' },
{
text: 'Request and response',
link: '/javalin/request-response',
collapsed: true,
items: [
{ text: 'Query params', link: '/javalin/query-params' },
{ text: 'URL params', link: '/javalin/url-params' },
{ text: 'Body and headers', link: '/javalin/body-and-headers' }
]
},
{ text: 'Sending errors', link: '/javalin/sending-errors' },
]
},
{
text: 'Server side rendering',
items: [
{ text: 'Static files', link: '/javalin/static-files' },
{ text: 'Views and templates', link: '/javalin/views-and-templates' },
{ text: 'Using loops', link: '/javalin/using-loops' },
{ text: 'Template partials', link: '/javalin/template-partials' },
{ text: 'CSS and assets', link: '/javalin/css-and-assets' },
{ text: 'User input', link: '/javalin/user-input' }
]
}
]
9 changes: 9 additions & 0 deletions .vitepress/sidebars/topnav.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ export const topnav = [
link: '/dotnet/'
}
]
},
{
text: 'Java',
items: [
{
text: 'Javalin',
link: '/javalin/'
}
]
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion src/express/web-socket-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ server.on('connection', (socket) => {
})
```

When the `'connection'` even is emitted, we are passed a web socket, which we
When the `'connection'` event is emitted, we are passed a web socket, which we
can call whatever we want (here, we used `socket`).

## Listening for socket events
Expand Down
4 changes: 4 additions & 0 deletions src/java/maven.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Creating a Maven project

##

128 changes: 128 additions & 0 deletions src/javalin/adding-a-model-layer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Adding a model layer

We'll need to create the _model_ layer and the _data access layer_. These are the parts of our application that deals with handling data models and persisiting data using the database.

## Models and Repositories

Models are classes that we use to represent data within the application.

```java
package com.corndel.bleeter.models;

public class User {
private Integer id;
public String username;
public boolean verified;

public User(Integer id, String username, boolean verified) {
this.id = id;
this.username = username;
this.verified = verified;
}

public Integer getId() {
return id;
}
}
```

Repositories are classes that interact with the database to let us persist, modify, and delete this data.


```java
package com.corndel.bleeter.repositories;

import com.corndel.bleeter.models.User;
import com.corndel.bleeter.DB;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class UserRepository {
public static List<User> findAll() throws SQLException {
var query = "SELECT id, username, verified FROM users";

try (var connection = DB.getConnection();
var statement = connection.createStatement();
var resultSet = statement.executeQuery(query);) {

var users = new ArrayList<User>();
while (resultSet.next()) {
var id = resultSet.getInt("id");
var username = resultSet.getString("username");
var verified = resultSet.getBoolean("verified");
users.add(new User(id, username, verified));
}
return users;
}
}
}
```

## Querying with substitutions

JDBC lets us set up _Prepared Statements_. These let us substitute in parameters to our SQL queries.

```java
public static User findById(id) {
var query = "SELECT id, username, verified FROM users WHERE id = ?"; // [!code highlight]
try (var connection = DB.getConnection();
var statement = connection.prepareStatement(query)) { // [!code highlight]
statement.setInt(1, id) // [!code highlight]
try (var resultSet = statement.executeQuery()) {
if (!resultSet.next()) {
return null;
}
var id = resultSet.getInt("id");
var username = resultSet.getString("username");
var verified = resultSet.getBoolean("verified");
return new User(id, username, verified);
}
}
}
```

::: danger

Do not be tempted to interpolate raw arguments into the query string. This opens
you up to SQL injection attacks.

Consider

```java
User.findById("3; DROP TABLE users;");
```

Always use prepared statements!

:::

## Inserting data

We can use an `INSERT` query with several parameters by putting more `?` and
passing the substitutions in with `.setString()`, `.setInt()`, or the appropriate set method for the datatype:

```java
public static User create(username, verified) {
var query = // [!code highlight:2]
"INSERT INTO users (username, verified) VALUES (?, ?) RETURNING *";

try (var connection = DB.getConnection();
var statement = con.prepareStatement(query)) {
statement.setString(1, username); // [!code highlight]
statement.executeUpdate(); // [!code highlight]

try (var resultSet = statement.getResultSet()) {
rs.next()
var id = rs.getInt("id");
return new User(id, username, verified)
}
}
}
```

::: info

Note the `RETURNING *` causes the statement to have a `resultSet` after execution. This lets us get the `id` and other fields of the newly created `User` from the database.

:::
Empty file added src/javalin/adding-css.md
Empty file.
Empty file added src/javalin/auth.md
Empty file.
78 changes: 78 additions & 0 deletions src/javalin/body-and-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Body and headers

## Headers

When we send a request, the headers are available in the backend as `ctx.header(String)`.

## Endpoints with body

### Accessing the body text

### Form data

### JSON

When we send a request with a JSON body, we can use `ctx.bodyAsClass(Some.class)` to parse the JSON into an object using a class.

::: code-group

```java{8-10,13-18} [server]
public class App {
private Javalin app;
public App() {
app.post(
"/users",
ctx -> {
var body = ctx.bodyAsClass(UserRequestBody.class);
var newUser = UserRepository.create(body.username, body.verified);
res.status(HttpStatus.CREATED).json(newUser);
});
}
class UserRequestBody {
public String username;
public boolean verified;
public UserRequestBody() {}
}
}
```

```bash{3} [client]
curl -v -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{"username": "MinnieMouse", "verified": true}'
> POST /users HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 45
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 47
< Date: Thu, 22 Feb 2024 16:57:57 GMT
{
"id": 21,
"username": "MinnieMouse",
"verified": 1
}
```

:::

Since the `ctx.bodyAsClass()` method uses the Jackson ObjectMapper under the hood, it needs a default constructor. It will then fill in the public fields that match betwwen the class and the JSON body.

::: tip

According to the
[HTTP standard](https://www.rfc-editor.org/rfc/rfc9110.html#name-terminology-and-core-concep),
`GET` requests cannot have a body, so we generally only use body in requests
with `POST`, `PUT` and `PATCH`.

:::
Loading

0 comments on commit 8bdafbb

Please sign in to comment.