Salt is a simple application framework that features an inversion of control container for usage with Kotlin.
-
Create new Gradle project with Kotlin/JVM as main language
-
Insert the Salt framework with
git submodule add https://github.com/kurbaniec-tgm/salt.git saltundersrc/main/kotlin/[main-package]Note: Do not work directly in the
saltpackage! Create a second package for your code. -
Use
gradle initSaltundersrc/main/kotlin/[main-package]/saltto initialize the framework -
Add the following dependencies to your
build.gradle:implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' compile 'org.jetbrains.kotlin:kotlin-test' compile 'org.jetbrains.kotlin:kotlin-test-junit' compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.3.60' compile group: 'org.mongodb', name: 'mongo-java-driver', version: '3.9.1' compile 'net.sourceforge.htmlunit:htmlunit:2.36.0' -
Lastly, define a
main-method that starts the Salt application:class Main { companion object { @JvmStatic fun main(args: Array<String>) { val app = SaltApplication() } } }
Just mark a class with @Scan and use @Autowired on a property with the same name/type in another class to automatically inject an instance of the scanned class to the property. Note, the class in which the object is injected also needs to be marked with @Scan or a annotation that includes it like @Controller.
@Scan
class AutowiredTest {
val value = "Test"
}@Scan
class SomeClass {
@Autowired
lateinit var autowiredTest: AutowiredTest
}Salt can serve any file you want, just drop it into the resources/web directory.
To configure request mappings for HTML-files create a new Controller class (annotated with @Controllerand define mapping functions.
A mapping functions consists of a method type annotation (@Get or @Post ) that contains the request path. The function itself returns a String, that is the filename of the page that should be returned without .html.
Following code shows how to return a HTML page on the request path / based on the file index.html-
@Controller
class Controller {
@Get("/")
fun index(): String {
return "index"
}
}At the moment the mapping functions can also return simple HTTP-responses for simple data transfer through the HTTP-body.
Following code shows how to transport two parameters ("Hi" and "Salt") to an client, when it sends a post request at /api.
@Controller
class Controller {
@Post("/api")
fun api(): HTTPTransport {
return HTTPTransport(HTTPTransport.Body("Hi", "Salt")).ok()
}
}The custom template parser is inspired by Thymeleaf and supports for now following functionality:
-
<span th:text="Hello, ${message}"></span>
The
th:textattribute will replace the value between tags eg.span.${message}stands for an object that is added in the controller viamodel.addAttribute("message", "baum"). So the ouput, when parsed will be<span>Hello, baum</span>. If baum is for example not a String but an other object likeUseradded asuserwith a attributelogin, you can also acces it via${user.login}. -
<a th:href="@{/some/path/${testo}}">Link!</a>
Creates a link that can refer to other pages or resources of the application. As seen, you can add also models like
${testo}that will be resolved to create a dynamic link. -
<th:block th:each="user : ${users}"> <span th:text="user ${user.id}"></span> </th:block>
Creates a loop of a block marked with
th:block.usersis a list added via a model in the controller. For every entry ofusersmarked asuserthe block will be dynamically created.
Note: No<th:block>will be seen on the parsed site.
To enable the template engine, the html-page needs to be mapped in an controller an contain a Model object in the function call. All the information that you want to parse need to be added to the Model object.
You have a page that contains following template code:
<span th:text="Hello, ${message}"></span>
<th:block th:each="user : ${users}">
<span th:text="user ${user.id}"></span>
</th:block>Then you can use following code to return the page at /template with injected values.
@Controller
class Controller {
@Get("/template")
fun template(m: Model): String {
data class User(val id: Int)
m.addAttribute("message", "Salt")
m.addAttribute("users", listOf(User(0), User(1)))
return "template"
}
}The following result should be seen when visiting /template now.
Salt makes performing CRUD operations on a remote Mongo database very easy.
To enable the MongoDB plugin, add the following configuration to resources\config.toml
[mongo]
enable = true
uri = "mongodb://localhost:27017"
db = "dev"
UserRepo = "users"This way Salt connects on startup to the remote database and binds the configuration interface UserRepo to the users collection in the dev database of MongoDB.
Now the UserRepo interface needs to be created and marked with the @MondoDB annotation. It also needs to implement the MongoRepo witch the type that we want to serialize to the database and String as second argument. With the implementation we gain a lot of basic functions like ìnsert or findAll.
But the true magic is, that you can easily define your own queries. Lets say the class User has a property username. Then you can create an abstract method fun findByUsername(username: String): List<User>? that generates the query for you and that you can call at runtime. You can also look after more parameters in a query to the inclusion of And.
Following code show some possible queries.
@MongoDB
interface UserRepo: MongoRepo<User, String> {
fun findByUsername(username: String): List<User>?
fun findByUsernameAndPassword(username: String, password: String): List<User>?
fun findByMyidAndUsername(myid: String, username: String): List<User>?
fun findByMyidAndUsernameAndPassword(myid: String, username: String, password: String): List<User>?
fun findByMyid(myid: String): List<User>?
}To use the MongoRepo in your code to perform CRUD-operations, just use the Salt dependency injection.
In this case that would look like that:
@Autowired
lateinit var userRepo: UserRepoClasses can for now not end with Kt or $1 because Kotlin creates [className](Kt|$1).class files, that are ignored while scanning for annotations.
The Salt framework includes many more features. Visit the complete documentation here or check out the source code of fully fledged Salt-applications like KPM.
Some aspects of the application can be configured in the configuration file found underresources\config.toml. Here are some of the most important ones:
[Server]:
ip_address: The ip-address the server is bound to.https_port: The port the server listens to https-requests.- Note: There is also a
http_portsetting, but you should not use the http-protocol with sensitive data in use.
You can disable it withhttp = false.
- Note: There is also a
[Security]:
timeout: The time, in which the user is automatically logged out when no request is send in the meantime. In minutes.password_timeout: The timeout, in which a user can not log in, because he used a wrong password to often. In minutes.password_fails: Sets the amount of bad authentication needed to trigger the login timeout.
[Keystore]:
generate: Usetrueif you want to automatically create a certificate for the https-encryption. Be aware that this certificate is not signed by any authority and therefore not trusted by most browsers. If you have a valid certificate usefalseand fill thefile-attribute.file: If you have a TLS-certificate for your domain, convert it into a java-keystore (.jks-file) and put it into theresfolder. Thefile-attribute should be the name of this file.password: The password the generated certificate should use or the password to your own keystore.
[Mongo]:
uri: The connection description to your MongoDB-database in the "String URI Format". Click [here][5] for more information.UserRepo: Name of your collection that will store user-accounts.PasswordRepo: Name of your collection that will store password-entity data.
MIT
GitHub kurbaniec · Mail at.kacper.urbaniec@gmail.com