Bütün detaylarına girersem bu yazı bir yazı dizisine dönüşür. :) Fakat 4 temel + 2 tamamlayıcı bileşen ile böyle bir web sitesini oluşturmak için kendi tecrübelerime dayanarak birkaç kilometre taşını belirtebilir ve açıklayabilirim. İlerleyen günlerde Yazılım kategorisinde bazı konularda detaylı yazılar da paylaşabilirim. Şimdilik ilk adımı atalım. Ben bir yazılımcıyım ve güncel ve yaygın teknolojiler kullanarak bir web sitesi hazırlamak istiyorum diyorsanız buyurun.
Günümüzde çok yaygın kullanılan spring framework yazılım geliştirme metodolojisini değiştirmekte ve spring boot altyapısı ile hızlandırmaktadır. İlk aşamada bize lazım olan bir spring boot projesidir. Bunun için Spring Initilizr adresine gidip aşağıdaki resimdeki gibi bir template oluşturabilirsiniz.
Bu ekranda sol taraftakiler tamamlayıcı teknolojilerden birisi olan maven için gerekli. Bu bilgiler sayesinde maven projenize bir hiyerarşik yapı verecek ve paketleyecek. Proje çıktısı jar olabilir çünkü spring boot aslında içinde bir main class olan uygulamadır.
İlk sıradaki dependency devtools sayesinde projeniz güncellediğinizde hemen derlenir ve kendi içindeki sunucuya deploy edilir. Bu yüzden ekstra bir tomcat gibi bir sunucu ihtiyacınız olmaz. Run as spring boot application seçeneği ile projeniz ayağa kalkar ve localhost://8080 'de çalışmaya başlar.
İkinci sıradaki Lombok şart olmayan bir kütüphanedir. Kodunuz içerisinde entitiy 'leriniz olacak ve bu entity 'ler getter setter ve constructor metodları içermek zorunda kalacak. Lombok sayesinde bu kodları tekrar tekrar yazmak zorunda kalmazsınız. Eclipse ile çalışabilmesi için Web Sitesinden bir eklenti indirip kurmanız gerekmektedir.
Sonraki Spring Web az önce söylediğim web uygulaması olarak çalışmasını sağlıyor. İçerisinde tomcat otomatik olarak geliyor ve devtools ile buraya deploy ediliyor. Run on server yerine run as spring boot aplication ile ayağa kalkıyor. Spring boot bu şekilde sizi tembelleştirerek işleri hallediyor. :)
Thymeleaf ise MVC dizaynı ile kullanabileceğiniz güzel bir html etikek kütüphanesi yani tag library. Önyüze aktarılan bilgileri çeşitli yapılarda html verisine dönüştürüyorsunuz mesela th:each gibi bir komut ile bir elemanı for döngüsü gibi çoğaltabiliyorsunuz. Spring framework ile iç içe çok verimli çalışabiliyorlar. Detaylar burada.
Bir sonraki ise Spring Security ile erişim kontrolü, şifre koruması veya cross site script koruması gibi işlevleri olabiliyor. Bu konuda derinlemesine bilgim yok fakat spring securty 'yi sitenizin admin sayfası için kullanacaksınız muhtemelen. :)
Spring data JPA ise veritabanı işlemlerinizi native sql ifadeleri yazmadan gerçekleştirebilmenizi sağlıyor. Aynı zamanda veri modellerinizi (entity) kodunuz içerisinde yazdığınız sınıflarla tanımlamanızı ve güncellemenizi de sağlayarak geliştirme sürecini anlaşılır ve hızlı hale getirebiliyor.
MS SQL Server Driver yerine farklı veritabanları (MySql, Oracle, PostgreSql gibi) kullanılabilir. Bu dependency örnek olması açısından burada. Fakat bir veritabanına bağlanmak için bu teknolojilerden herhangi birini kullanmanız şart.
Arayüz için thymeleaf kütüphanesinin özelliklerinden yararlanacağız fakat profesyonel css javascript arayüzleri yazamıyorsanız veya angular react gibi kütüphaneler konusunda bilginiz yoksa (benim gibi) internette hazır çok sayıda template bulunuyor. Tabi bir link ile tasarımı yapan siteye atıfta bulunarak. Ben ColorLib ile template bulup üzerine kod ile geliştirme yapmayı tercih ettim. Çoğunlukla wordpress temaları olsa da html + bootsrap (yani css) ile hazırlanmış şablonları da var.
Bir tema bulup veya hazırlayıp projeye dahil ettikten sonra (templates altındaki index.html sayfası mesela) projenin eclipse 'de aşağıdakine benzer bir yapıda görünmesi lazım. Eclipse 'de Import Existing Maven Project işlemi ile tabi.
Eclipse için marketten Spring Tools Suite eklentisini de kurmayı unutmamalısınız.Üstteki MysiteApplication.java main class 'tır ve spring boot 'u harekete geçirir. Resources altındaki static klasörü içinde resim, css, javascript dosyaları yer almalıdır. Thymeleaf ve spring boot ikilisi bu klasörü yapısı ile çalışır. Templates klasörü ise web sayfalarınız olacaktır. Index.html burada mesela. application.properties uygulamanın kullanacağı esas bilgileri içerecektir. Veritabanı bağlantıları loglama seviyesi mail sunucusu ...vs gibi. En alttaki pom.xml ise bağımlılıkları ve derleme işlemin yöneten xml konfigürasyonudur.
Bu proje şu anda run as -> spring boot application şeklinde çalıştırılmaya hazırdır teknik olarak fakat spring boot ayağa kalkarken mssql driver yüzünden veritabanı bağlantı bilgileri isteyecektir. Örnek olarak mssql için application.properties dosyasında aşağıdaki gibi bilgiler gerekecektir:
spring.datasource.url = jdbc://adres:port; databaseName=mysitedatabase;
spring.datasource.driverClassName = com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.username = username
spring.datasource.password = password
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.SQLServer2012Dialect
spring.security.user.name = admin
spring.security.user.password = password
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext
Bu şekilde kullandığınız veritabanı bilgilerini yazdıktan sonra http://localhost:8080/index.html adresine gittiğinizde karşınıza kapı gibi spring security çıkar ve kullanıcı adı şifre ister. Properties 'deki gibi spring.security.user.name ve password ile geçebilirsiniz. (Evet 404 gibi bir hata alacaksınız geçince ama o sonra)
Security 'yi tabi sadece admin sayfası gibi alanlarda yapacaksınız muhtemelen. Bunun için aşağıdaki gibi bir sınıfı projeye dahil etmelisiniz. /admin sayfası kullanıcı adı şifre isteyecek ve geri kalan sayfalar direkt olarak açılacaktır.
@Configuration
@EnableWebSecurity
public class CustomSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests().antMatchers("/admin").authenticated().and().formLogin();
http.authorizeRequests().antMatchers("/**").permitAll();
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
@Configuration sayesinde spring framework bu sınıfı konfigürasyon sınıfı olarak görür ve örneğin spring security 'yi ayağa kaldırırken bu annotation ile işaretlenmiş sınıflar arar. WebSecurityConfigurerAdapter sınıfından extend edildiği için güvenlik için kullanılacağı anlaşılır. Daha doğrusu spring security 'nin kullanabileceği bir bean olduğu anlaşılır.
Bu şekilde security ayarını basic seviyede yapmış oluyoruz ve anasayfamızı yani index sayfasını hazırlamaya geçiyoruz. Veritabanında tutacağınız hibernate entity 'lerini yani nesnelerini (tabloları) tanımlamak gerekiyor öncelikle. Çünkü açılan sayfada bir sorgu yapıp ekrana sonuç getireceğiz en basit anlamda. Bunun için bir örnek aşağıdaki gibi olabilir:
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "POST")
public class Post
{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_seq")
@SequenceGenerator(name = "post_seq", sequenceName = "post_seq", allocationSize = 1)
@Column(name = "ID", nullable = false)
private int id;
@Nationalized
@Column(name = "TITLE", nullable = false, length = 1500)
private String title;
@Nationalized
@Column(name = "CONTENT", nullable = false, length = 1000)
private String content;
@Nationalized
@Column(name = "SUMMARY", nullable = false, length = 2000)
private String summary;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CATEGORY", referencedColumnName = "ID", nullable = false)
private Category category;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "post")
@Where(clause = "active = 1")
private List<Comment> comments;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "post_tags", joinColumns = @JoinColumn(name = "post_ID"), inverseJoinColumns = @JoinColumn(name = "TAG_ID"))
private List<Tag> tags;
@Column(name = "PUB_DATE", nullable = false)
private Date publish_date = new Date();
}
@Entity tabi ki entity yani tablo olduğunu belirtiyor. @Getter, @Setter, @AllArgsConstructor, @NoArgsConstructor sayesinde Lombok kodları var sayıyor ve inject ediyor. Biz de boşuna tekrar tekrar yazmıyoruz. @Table ile veritabanındaki tablo ismini best practice olması adına belirtiyoruz.
Tabi buradaki join 'lerle ilgili söylenebilecek çok şey var ben örnek olarak n-1 Category, n-n Tag ve 1-n Comment sınıflarını da yazdım. Siz kendi sitenizde kendi veritabanı yapınızı geliştireceğiniz için detaylandırmanın mantığı olmayacak. Ama buna benzer ilişkiler mutlaka kuracaksınız.
@Nationalized ile MSSQL 'de türkçe karakter sorununu da çözüyorsunuz. Bu nesneleri yöneten veritabanı erişim sınıfı yazacaksınız tabi CRUD işlemleri için. İlk yazınızı yani post 'unuzu veritabanına manuel olarak eklediğinizi farz edersek basit bir örnek:
@Repository
public class SiteRepository
{
private EntityManager em;
@Autowired
public SiteRepository(EntityManagerFactory factory)
{
this.em = factory.createEntityManager();
}
public List<Post> get_all_posts()
{
List<Post> res = null;
Session session = em.unwrap(Session.class);
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Post> criteria_query = builder.createQuery(Post.class);
Root<Post> root = criteria_query.from(Post.class);
criteria_query.orderBy(builder.desc(root.get("publish_date")));
Query<Post> query = session.createQuery(criteria_query);
res = query.getResultList();
return res;
}
}
@Repository de @Component yada @Service gibi bir spring anotasyonudur. Veritabanına erişim yapan sınıflar için best practice olarak kullanılmaktadır. @CriteriaQuery ile Post sınıfından where koşulu olmadan sorgu çekiyor bu örnek. Ayrıca publish_date sütununua göre büyküten küçüğe sıralıyor. Criteria API deprecated olunca criteria query hayata geçti hibernate tarafında. Session nesneleri de EntityManager 'dan unwrap metodu ile kullanılıyor.
Sonrasında /index.html ile browser 'a gitmeye çalıştığınızda index sayfasını bulamadım hatası alacaksınız. Burada bir yönlendirme yapılması gerekiyor ve bunun için spring framework 'ün controller yapısını kullanacaksınız. Burada veritabanı işlemleri de var tabi repository ve entity sınıflarımız hazır. ModelAndView nesnesi ile index view 'unu döndürüyor ve içerisine post listesini ekliyoruz. Örnek:
@Controller
public class Maincontroller
{
private SiteRepository repository;
private List<Post> all_posts;
@Autowired
public Maincontroller(SiteRepository post_repository)
{
this.repository = post_repository;
this.all_posts = this.repository.get_all_posts();
}
@GetMapping(path =
{ "", "index", "index.html" })
public ModelAndView home()
{
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("posts", this.all_posts);
return modelAndView;
}
}
@Controller sayesinde spring boot ayağa kalkarken bu sınıfı ayağa kaldırır ve web isteklerini bu sınıfa yönlendirir. @Autowired ile repository sınıfımız da spring boot ile ayağa kaldırılıp bu sınıfa constructor aracılığı ile dahil edilir. @GetMapping ise bu controller 'ın home metodunun / veya /index veya /index.html şeklinde gelen GET isteklerine cevap vereceğini belirtir. Bu şekilde template 'in index sayfasını geitirmek için gereken back-end kodu hazır olmuş olur.
Bu post 'ları veritabanından çektikten sonra thymeleaf th:each yardımı ile ekranda listelemek için ise aşağıdakine benzer bir kod kullanabilirsiniz belki:
<div th:each="post: ${posts}">
<a th:href="@{'post?id=' + ${post.id}}" th:text="${post.title}"></a>
</div>
Blog yazılarınızı listeleyeceğiniz ilk ekranınız bu kadar kod ile hazır hale gelebiliyor. Bu noktadan sonra kendi isterlerinize göre kendi konfigürasyonunuzu yapmalısınız. Yukarıdaki kod örneklerini 1 gün içerisinde hayata geçirmeniz mümkün. Eğer yapacağınız yazılımı analiz etmişseniz bundan sonraki kısım tamamen bu yazılımı buna benzer kodlar ile geliştirmeye, spring, hibernate ve thymeleaf 'in özelliklerini kullanmaya kalıyor. Controller sınıfınız zamanla büyüyecektir. Veritabanında tuttuğunuz bilgiler ve repository sınıfınız değişecektir. Bu yazının amacı temel çerçeveyi oturtmaktı. Sizlere hatasız kodlamalar diliyorum ve bir sonraki yazıda görüşmek üzere :)
Now, if i want to get into every programmatical detail, this post would turn into a beginners course. :) But i think i can explain couple of milestones to develop a website like this using 4 fundamental + 2 complimentary technologies, all based on my experience. I might also write about different subjects in detail in the future under the Software category. Let's just take the first step for now. If you say i you are a software developer and you want to create a website by using commonly used popular technologies, here we go.
Spring Framework is widely used nowadays and it is bascially changing the way we create software. It is also accelerating it when used with Spring Boot infrastructure. First thing we need is going to be a Spring Boot application. You can create a template like i showed in the image below by visiting Spring Initilizr website.
The left side of the screen contains the necessary information for Maven, which is one of the complimentary technologies. Maven will form your project and source code and compile it in a packate with these information. The packaging of your project can be "jar" file since spring boot will provide a main method and a built-in apache tomcat server inside.
Our first dependency devtools will deploy your application on the built-in server, as soon as you save your code. This way you will not have to stop-start the application everytime you change the code. When you choode Run as -> Spring Boot Application, your website will be deployed and start serving from http://localhost:8080.
The second dependency, Lombok, is a non-obligatory library. Your code will have entities (database tables). And these entities will have to have getter, setter and constructor methods. Lombok will be injecting these methods without writing these boilerplate code over and over again. If you are going to use it Eclipse, you have to go to the Web Site and install the add-on.
The next one, Spring Web will give the necessary libraries to run as a web project. It will include an apache tomcat server inside and will run the website here. This way, you won't have to create a server manually and choose Run as -> Run on server. Insted you will be running as Spring Boot application. Spring boot will handle these operations, all the while making you ever more lazy. :)
Thymeleaf is basicaly a tag library where you can take advantage of MVD design pattern. This will enable you to convert the information into html output with spefific code structures. For example, when you use th:each command, the interpreter will turn it into a for loop and multpliy the element in the html page. It works very well with spring framework too. More on this is here.
The next dependency, Spring Security, is the access control library. It handles operations like password protections or cross site script attacks. I do not have extensive information about it but you will probably use it to secure your admin pages for the website. :)
Spring data JPA will help you query your database with codes rather than native queries. It will also boost your development process and make it easier to maintain, by allowing you to create and operate on your entities inside your code. To put it simply, less sql, more java.
MS SQL Server Driver can be replaced by other database vendors like MySql, Oracle, PostgreSql. This is the database driver (connection agent) and mssql is just an example. You can choose anyone you want. But you will inevitably use one.
We will be taking advantage of Thymeleaf properties on the frontend. But if you can't design your own user interface with css and javascript or you are not familiar with technologies like react, angular, vue.js (like me), you might have to start with an html template here. As long as you attribute the creator in your website with a link, you can find a number of free html bootsrap (css) templates to use. I found one in ColorLib. There are mostly wordpress templates but you can also find html + bootsrap templates too.
After you find or create a theme and include it inside the templates folder, the project should look something like the image below. Eclipse 'de Import Existing Maven Project işlemi ile tabi.
In eclipse, you should also install Spring Tools Suite from the marketplace too.
MysiteApplication class at the top is the main class which basically boots the spring boot. Resources folder will store your images, css files, javascript files inside the static folder. Thymeleaf and spring boot will be working with this structure. Templates folder will store your web pages. Notice Index.html is here. application.properties will hold the environment variable for the whole application. Database connection strigs, usernames and passwords, logging levels and ..etc will be here. pom.xml at the bottom will be used by Maven when compiling your application and will also hold the necessary depenceny information.
This project is basicaly ready to launch with Run as -> Spring Boot Application at this stage but it will look for database configuration to connect a database while launching. An example for MSSQL database connection properties inside the application.properties would be like this:
spring.datasource.url = jdbc://adres:port; databaseName=mysitedatabase;
spring.datasource.driverClassName = com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.username = username
spring.datasource.password = password
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.SQLServer2012Dialect
spring.security.user.name = admin
spring.security.user.password = password
spring.jpa.hibernate.ddl-auto = update
spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext
After writing the necessary information here, you can try to open http://localhost:8080/index.html in your browser, only to get a faceful of spring security in front of you. But you can pass this security layer by entering the spring.security.user.name and password properties in the application.properties file above. (Yes you will also get a 404 error after this but we will handle that later.)
If you are creating a blog like this, you will probably use the security for admin pages only. In order to tell spring security to intervene only for the admin pages and let the users browse other pages freely, you should include a class like this inside your application.
@Configuration
@EnableWebSecurity
public class CustomSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests().antMatchers("/admin").authenticated().and().formLogin();
http.authorizeRequests().antMatchers("/**").permitAll();
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
@Configuration means this class is a configuration file for spring boot. Shocker. For example, while the royal guard of spring security is awakening, spring boot will look for beans with this annotation. When you extend WebSecurityConfigurerAdapter class, this will indicate that this is the kind of configuration class for spring security.
This will establish the basic security settings for spring security. We can now move on to prepearing the data for index.html. First, let's define the hibernate entities (database tables). A simple entity example can be like this:
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "POST")
public class Post
{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_seq")
@SequenceGenerator(name = "post_seq", sequenceName = "post_seq", allocationSize = 1)
@Column(name = "ID", nullable = false)
private int id;
@Nationalized
@Column(name = "TITLE", nullable = false, length = 1500)
private String title;
@Nationalized
@Column(name = "CONTENT", nullable = false, length = 1000)
private String content;
@Nationalized
@Column(name = "SUMMARY", nullable = false, length = 2000)
private String summary;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "CATEGORY", referencedColumnName = "ID", nullable = false)
private Category category;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "post")
@Where(clause = "active = 1")
private List<Comment> comments;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "post_tags", joinColumns = @JoinColumn(name = "post_ID"), inverseJoinColumns = @JoinColumn(name = "TAG_ID"))
private List<Tag> tags;
@Column(name = "PUB_DATE", nullable = false)
private Date publish_date = new Date();
}
@Entity will let the spring boot know that this class should be treated as an entity, not like person or animal or something. @Getter, @Setter, @AllArgsConstructor, @NoArgsConstructor is perks of Lombok and these methods are injected while packaging. Thus getting rid of the boilerplate code. @Table annotation will indicate the database table name. This is the best practice.
There are also joins here that i have added as clues for you. This database structure is completely up to you but i wanted to give n-1 Category, n-n Tag and 1-n Comment classes as example. There is no necessity to go further details here since you will probably have a different approach.
@Nationalized annotation will solve the nationalized character problem in MSSQL. Now we need to write a database access method somewhere. Assuming you insert the first post inside your databse manually, i can give you a simple database access class like this:
@Repository
public class SiteRepository
{
private EntityManager em;
@Autowired
public SiteRepository(EntityManagerFactory factory)
{
this.em = factory.createEntityManager();
}
public List<Post> get_all_posts()
{
List<Post> res = null;
Session session = em.unwrap(Session.class);
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Post> criteria_query = builder.createQuery(Post.class);
Root<Post> root = criteria_query.from(Post.class);
criteria_query.orderBy(builder.desc(root.get("publish_date")));
Query<Post> query = session.createQuery(criteria_query);
res = query.getResultList();
return res;
}
}
@Repository is a spring framework stereotype annotation just like @Component or @Service. @Repository is the go to annotation for database operation classes. With the help of @CriteriaQuery, this example is selecting all the posts from Post table. Also ordering the result descending by publish_date column. Criteria query classes are now used since the Criteria API is deprecated. And EntityManager is provividing an unwrap method to create a database session.
Now you can actually try to go /index.html page but you will get a 404 error. You must provide a router here and you will be using controller classes of spring framework. There is also database queries here with our ready to use repository and entitiy classes. ModelAndView class will tell spring framework to prepare the index.html page (view) with the list of posts as extra information (model). Example:
@Controller
public class Maincontroller
{
private SiteRepository repository;
private List<Post> all_posts;
@Autowired
public Maincontroller(SiteRepository post_repository)
{
this.repository = post_repository;
this.all_posts = this.repository.get_all_posts();
}
@GetMapping(path =
{ "", "index", "index.html" })
public ModelAndView home()
{
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("posts", this.all_posts);
return modelAndView;
}
}
Spring boot will instantiate this class as a bean and use it to match web requests with views because it is annotated with @Controller annotation. @Autowired is basicaly telling spring boot to find a bean with SiteRepository type and inject it to the constructor on the boot time. @GetMapping is a web get request annotation that indicates this method will be responding to / or /index or /index.html requests. The necessary back-end code for index.html is ready at this stage.
The only step left to put these posts on the interface is to use thymeleaf specifications. You can use a structure like th:each on the frontend like this:
<div th:each="post: ${posts}">
<a th:href="@{'post?id=' + ${post.id}}" th:text="${post.title}"></a>
</div>
The first page where you may list your blog posts can be prepared with these couple of classes and code blocks. You must continue your journey by configuring, managing and implementing your own requirements after this point. You can get these codes to work in only 1 day with some experience. If you already know what kind of website are you going to develop, you will mostly using similar codes with spring, hibernate and thymeleaf. Your Controller class will eventually get bigger. The data you store in the database will evolve hence making complex repository classes. The purpose of this post is to give you the basics and guide you through the first baby steps. I wish you error-free coding and see you at the next post :)